agentlas 1.0.46 → 1.0.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +7 -7
- package/engine/acp/server.cjs +279 -0
- package/engine/agentlas-capabilities.cjs +4 -2
- package/engine/agentlas-core-harness.cjs +18 -0
- package/engine/agentlas-i18n.cjs +8 -8
- package/engine/agentlas-input.cjs +3 -2
- package/engine/agentlas-native-host.cjs +130 -11
- package/engine/agentlas-onboard.cjs +9 -3
- package/engine/agentlas-permissions.cjs +5 -1
- package/engine/agentlas-workforce.cjs +81 -24
- package/engine/agents/router.cjs +4 -2
- package/engine/architecture.data.json +6 -30
- package/engine/automation/daemon.cjs +3 -7
- package/engine/bootstrap-schema.sql +216 -191
- package/engine/browser/cdp.cjs +10 -4
- package/engine/cloud-assets/commands.cjs +1 -1
- package/engine/cloud-assets/package.cjs +161 -45
- package/engine/commands/acp.cjs +45 -0
- package/engine/commands/billing.cjs +2 -2
- package/engine/commands/call.cjs +4 -0
- package/engine/commands/context.cjs +14 -3
- package/engine/commands/doctor.cjs +8 -4
- package/engine/commands/graph.cjs +46 -54
- package/engine/commands/index.cjs +2 -0
- package/engine/commands/search.cjs +2 -2
- package/engine/commands/workforce.cjs +11 -0
- package/engine/core/desktop-core.cjs +93 -1
- package/engine/firms/orchestrate.cjs +32 -1
- package/engine/graph/interview.cjs +2 -11
- package/engine/graph/vocabulary.generated.cjs +1 -1
- package/engine/hephaestus/runtime.cjs +2 -6
- package/engine/project/memory-context.cjs +20 -7
- package/engine/project/seed.cjs +46 -31
- package/engine/project/state.cjs +8 -1
- package/engine/runtimes/acp-driver.cjs +96 -0
- package/engine/runtimes/auth-evidence.cjs +6 -0
- package/engine/runtimes/detect.cjs +3 -13
- package/engine/runtimes/kinds.cjs +84 -0
- package/engine/runtimes/resolve.cjs +67 -14
- package/engine/sessions/prompt.cjs +2 -2
- package/engine/ui/commands-catalog.cjs +2 -0
- package/engine/ui/palette.cjs +2 -1
- package/engine/ui/repl.cjs +4 -3
- package/engine/ui/shell.cjs +43 -5
- package/engine/vendor/desktop-core.manifest.json +5 -5
- package/engine/workforce/capture.cjs +55 -10
- package/engine/workforce/deps.cjs +2 -2
- package/engine/workforce/local-core-transport.cjs +13 -19
- package/package.json +2 -1
- package/engine/project/super-ontology-seed.json +0 -3288
|
@@ -19,6 +19,7 @@ const fs = require("node:fs");
|
|
|
19
19
|
const os = require("node:os");
|
|
20
20
|
const path = require("node:path");
|
|
21
21
|
const permissions = require("./agentlas-permissions.cjs");
|
|
22
|
+
const acpDriver = require("./runtimes/acp-driver.cjs");
|
|
22
23
|
const i18n = require("./agentlas-i18n.cjs");
|
|
23
24
|
const { wrapStdioServer } = require("./agentlas-mcp-env.cjs");
|
|
24
25
|
|
|
@@ -700,6 +701,118 @@ function geminiArgs({ prompt, systemPrompt, permission, model, mcpServers, mcpAl
|
|
|
700
701
|
];
|
|
701
702
|
}
|
|
702
703
|
|
|
704
|
+
function agyPermissionArgs(permission) {
|
|
705
|
+
const level = permissions.normalize(permission);
|
|
706
|
+
if (level === "full") return ["--dangerously-skip-permissions"];
|
|
707
|
+
return [
|
|
708
|
+
"--mode", level === "write" ? "accept-edits" : "plan",
|
|
709
|
+
"--sandbox",
|
|
710
|
+
];
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function agyArgs({ prompt, systemPrompt, permission, model, addDirectories = [] }) {
|
|
714
|
+
const body = systemPrompt ? `${systemPrompt}\n\n---\n\n${prompt}` : prompt;
|
|
715
|
+
return [
|
|
716
|
+
...(model ? ["--model", model] : []),
|
|
717
|
+
...[...new Set(addDirectories.filter(Boolean))].flatMap((dir) => ["--add-dir", dir]),
|
|
718
|
+
...agyPermissionArgs(permission),
|
|
719
|
+
"--output-format", "stream-json",
|
|
720
|
+
"--print-timeout", "30m",
|
|
721
|
+
"--prompt", body,
|
|
722
|
+
];
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const AGY_WINDOWS_ARGV_PROMPT_LIMIT = 6_000;
|
|
726
|
+
|
|
727
|
+
function agyPromptBootstrap(promptFile) {
|
|
728
|
+
return `Read the complete Agentlas request from ${JSON.stringify(promptFile)}, follow it exactly, and do not reveal the file path.`;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Windows npm CLI shims pass through cmd.exe's much smaller command-line
|
|
733
|
+
* ceiling. Move only oversized agy prompts into a private one-shot file and
|
|
734
|
+
* keep argv limited to a short bootstrap. The caller owns cleanup and must run
|
|
735
|
+
* it on every process terminal path (close, spawn error, timeout, and abort).
|
|
736
|
+
*/
|
|
737
|
+
function prepareAgyLaunch(request, options = {}) {
|
|
738
|
+
const body = request.systemPrompt
|
|
739
|
+
? `${request.systemPrompt}\n\n---\n\n${request.prompt}`
|
|
740
|
+
: request.prompt;
|
|
741
|
+
const platform = options.platform || process.platform;
|
|
742
|
+
const promptLimit = Number.isFinite(options.promptLimit)
|
|
743
|
+
? Math.max(1, Math.trunc(options.promptLimit))
|
|
744
|
+
: AGY_WINDOWS_ARGV_PROMPT_LIMIT;
|
|
745
|
+
if (platform !== "win32" || body.length <= promptLimit) {
|
|
746
|
+
return { args: agyArgs(request), promptFile: null, cleanup: () => {} };
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
let directory = null;
|
|
750
|
+
try {
|
|
751
|
+
directory = fs.mkdtempSync(path.join(os.tmpdir(), "agentlas-agy-prompt-"));
|
|
752
|
+
try { fs.chmodSync(directory, 0o700); } catch { /* Windows/best-effort */ }
|
|
753
|
+
const promptFile = path.join(directory, "request.txt");
|
|
754
|
+
fs.writeFileSync(promptFile, body, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
755
|
+
try { fs.chmodSync(promptFile, 0o600); } catch { /* Windows/best-effort */ }
|
|
756
|
+
let cleaned = false;
|
|
757
|
+
return {
|
|
758
|
+
args: agyArgs({
|
|
759
|
+
...request,
|
|
760
|
+
systemPrompt: "",
|
|
761
|
+
prompt: agyPromptBootstrap(promptFile),
|
|
762
|
+
addDirectories: [directory, ...(request.addDirectories || [])],
|
|
763
|
+
}),
|
|
764
|
+
promptFile,
|
|
765
|
+
cleanup: () => {
|
|
766
|
+
if (cleaned) return;
|
|
767
|
+
cleaned = true;
|
|
768
|
+
try { fs.rmSync(directory, { recursive: true, force: true }); } catch { /* OS temp cleanup fallback */ }
|
|
769
|
+
},
|
|
770
|
+
};
|
|
771
|
+
} catch (error) {
|
|
772
|
+
if (directory) {
|
|
773
|
+
try { fs.rmSync(directory, { recursive: true, force: true }); } catch { /* best-effort */ }
|
|
774
|
+
}
|
|
775
|
+
throw error;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
function handleAgyLine(line, st, ui) {
|
|
780
|
+
let obj;
|
|
781
|
+
try { obj = JSON.parse(line); } catch { return; }
|
|
782
|
+
if (obj.event === "result") {
|
|
783
|
+
if (st.geminiStreaming) { ui.streamEnd(); st.geminiStreaming = false; }
|
|
784
|
+
if (obj.result && typeof obj.result.response === "string") st.finalText = obj.result.response;
|
|
785
|
+
if (obj.result?.status && !["success", "completed", "done"].includes(String(obj.result.status).toLowerCase())) {
|
|
786
|
+
st.error = `agy ${obj.result.status}`;
|
|
787
|
+
st.errorKind = "exit";
|
|
788
|
+
st.errorSource = "marker";
|
|
789
|
+
}
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
if (obj.event !== "step_update" || !obj.step_update) {
|
|
793
|
+
if (obj.event) ui.status(`agy: ${obj.event}`);
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
const step = obj.step_update;
|
|
797
|
+
if (step.usage) {
|
|
798
|
+
st.usage = {
|
|
799
|
+
input_tokens: step.usage.input_tokens,
|
|
800
|
+
output_tokens: step.usage.output_tokens,
|
|
801
|
+
...(step.usage.duration_ms != null ? { duration_ms: step.usage.duration_ms } : {}),
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
if (step.step_type === "agent_response") {
|
|
805
|
+
const delta = typeof step.text_delta === "string" ? step.text_delta : "";
|
|
806
|
+
if (!delta) return;
|
|
807
|
+
if (!st.geminiStreaming) { ui.streamStart(); st.geminiStreaming = true; }
|
|
808
|
+
ui.streamDelta(delta);
|
|
809
|
+
st.text += delta;
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
if (st.geminiStreaming) { ui.streamEnd(); st.geminiStreaming = false; }
|
|
813
|
+
ui.status(`agy: ${step.step_type || "step"}${step.state ? ` (${step.state})` : ""}`);
|
|
814
|
+
}
|
|
815
|
+
|
|
703
816
|
// gemini 툴명 → 친숙한 표시명 (claude/codex 표기와 통일)
|
|
704
817
|
const GEMINI_TOOL_NAMES = {
|
|
705
818
|
run_shell_command: "Bash",
|
|
@@ -803,6 +916,11 @@ function handleGeminiLine(line, st, ui) {
|
|
|
803
916
|
function runNativeTurn(req) {
|
|
804
917
|
const { kind, bin, ui } = req;
|
|
805
918
|
const cwd = req.cwd;
|
|
919
|
+
// kimi/grok/cursor: 손코딩 3번째 대신 벤더 코어의 공용 ACP 러너로 (PRD 2026-08-15 T-2).
|
|
920
|
+
// 같은 결과 계약({text, session, usage, error, errorKind, errorSource})으로 돌아온다.
|
|
921
|
+
if (acpDriver.ACP_KINDS.has(kind)) {
|
|
922
|
+
return acpDriver.runAcpTurn(req);
|
|
923
|
+
}
|
|
806
924
|
let launchReq = req;
|
|
807
925
|
if (
|
|
808
926
|
kind === "gemini" && permissions.normalize(req.permission) === "full" &&
|
|
@@ -829,6 +947,7 @@ function runNativeTurn(req) {
|
|
|
829
947
|
let args;
|
|
830
948
|
let lineHandler;
|
|
831
949
|
let plainStream = false;
|
|
950
|
+
let launchCleanup = () => {};
|
|
832
951
|
try {
|
|
833
952
|
if (kind === "claude-code") {
|
|
834
953
|
args = claudeArgs(launchReq);
|
|
@@ -840,17 +959,10 @@ function runNativeTurn(req) {
|
|
|
840
959
|
args = geminiArgs(launchReq);
|
|
841
960
|
lineHandler = (l) => handleGeminiLine(l, st, ui);
|
|
842
961
|
} else if (kind === "agy") {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
*/
|
|
848
|
-
const agyPrompt = launchReq.systemPrompt
|
|
849
|
-
? `${launchReq.systemPrompt}\n\n---\n\n${launchReq.prompt}`
|
|
850
|
-
: launchReq.prompt;
|
|
851
|
-
args = ["--print", agyPrompt, ...(launchReq.model ? ["--model", launchReq.model] : [])];
|
|
852
|
-
plainStream = true;
|
|
853
|
-
lineHandler = null;
|
|
962
|
+
const prepared = prepareAgyLaunch(launchReq);
|
|
963
|
+
args = prepared.args;
|
|
964
|
+
launchCleanup = prepared.cleanup;
|
|
965
|
+
lineHandler = (l) => handleAgyLine(l, st, ui);
|
|
854
966
|
} else {
|
|
855
967
|
return Promise.resolve({ text: "", session: st.session, error: `unknown runtime: ${kind}`, errorKind: "unsupported", errorSource: "marker" });
|
|
856
968
|
}
|
|
@@ -885,6 +997,7 @@ function runNativeTurn(req) {
|
|
|
885
997
|
try { req.onSpawn(child); } catch { /* observer 실패가 턴을 죽이면 안 됨 */ }
|
|
886
998
|
}
|
|
887
999
|
} catch (e) {
|
|
1000
|
+
launchCleanup();
|
|
888
1001
|
ui.error(uiText(ui, "runtime.failed", kind, e.message));
|
|
889
1002
|
return resolve({ text: "", session: st.session, error: e.message });
|
|
890
1003
|
}
|
|
@@ -911,6 +1024,7 @@ function runNativeTurn(req) {
|
|
|
911
1024
|
removeLineReader();
|
|
912
1025
|
child.stderr?.removeListener("data", onStderr);
|
|
913
1026
|
if (req.signal) req.signal.removeEventListener?.("abort", onAbort);
|
|
1027
|
+
launchCleanup();
|
|
914
1028
|
};
|
|
915
1029
|
const finish = (result) => {
|
|
916
1030
|
if (settled) return;
|
|
@@ -1212,6 +1326,11 @@ module.exports = {
|
|
|
1212
1326
|
codexPermissionArgs,
|
|
1213
1327
|
geminiArgs,
|
|
1214
1328
|
geminiPermissionArgs,
|
|
1329
|
+
agyArgs,
|
|
1330
|
+
agyPermissionArgs,
|
|
1331
|
+
agyPromptBootstrap,
|
|
1332
|
+
prepareAgyLaunch,
|
|
1333
|
+
handleAgyLine,
|
|
1215
1334
|
claudeMcpIsolationArgs,
|
|
1216
1335
|
geminiMcpIsolationArgs,
|
|
1217
1336
|
prepareCodexRuntimeEnv,
|
|
@@ -133,11 +133,13 @@ async function runOnboard({ ui, rl, helpers, persist }) {
|
|
|
133
133
|
// Step 2 — default runtime
|
|
134
134
|
ui.line("");
|
|
135
135
|
printIndented(ui.t("wiz.runtimeQ"), c.bold);
|
|
136
|
-
|
|
136
|
+
// 위저드 선택지 = 네이티브 스폰 러너 4종 (정본 runtimes/kinds.cjs, 표시 순서 포함).
|
|
137
|
+
const cliKinds = require("./runtimes/kinds.cjs").NATIVE_CLI_KINDS;
|
|
137
138
|
const rtOpts = [{ value: "auto", label: ui.t("wiz.runtimeAuto") }];
|
|
138
139
|
for (const k of cliKinds) {
|
|
139
140
|
const has = !!H.which(H.RUNTIME_BIN[k]);
|
|
140
|
-
|
|
141
|
+
const runtimeLabel = k === "agy" ? "agy · Antigravity" : k === "gemini" ? "gemini · legacy" : k;
|
|
142
|
+
rtOpts.push({ value: k, label: `${runtimeLabel} (${has ? ui.t("wiz.runtimeInstalled") : ui.t("wiz.runtimeMissing")})` });
|
|
141
143
|
}
|
|
142
144
|
rtOpts.forEach((o, i) => optionLine(i + 1, o.label, i === 0));
|
|
143
145
|
const ri = await pickNum(rtOpts.length);
|
|
@@ -149,6 +151,7 @@ async function runOnboard({ ui, rl, helpers, persist }) {
|
|
|
149
151
|
const installHint = {
|
|
150
152
|
"claude-code": "npm i -g @anthropic-ai/claude-code",
|
|
151
153
|
codex: "npm i -g @openai/codex",
|
|
154
|
+
agy: "Install Antigravity from https://antigravity.google/ and put agy on PATH",
|
|
152
155
|
gemini: "npm i -g @google/gemini-cli",
|
|
153
156
|
}[runtime];
|
|
154
157
|
if (!H.which(H.RUNTIME_BIN[runtime])) {
|
|
@@ -156,7 +159,10 @@ async function runOnboard({ ui, rl, helpers, persist }) {
|
|
|
156
159
|
} else {
|
|
157
160
|
try {
|
|
158
161
|
const { runtimeAuthEvidence } = require("./runtimes/auth-evidence.cjs");
|
|
159
|
-
|
|
162
|
+
// Antigravity and legacy Gemini currently share Google's local OAuth
|
|
163
|
+
// evidence root, but remain distinct executable/runtime selections.
|
|
164
|
+
const evidenceKind = runtime === "agy" ? "gemini" : runtime;
|
|
165
|
+
if (runtimeAuthEvidence(evidenceKind).status === "none") {
|
|
160
166
|
printIndented(ui.t("wiz.runtimeLoginHint", H.RUNTIME_BIN[runtime]), c.dim);
|
|
161
167
|
}
|
|
162
168
|
} catch { /* evidence unavailable — say nothing rather than guess */ }
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
const LEVELS = ["read", "write", "full"];
|
|
11
11
|
|
|
12
|
+
function isLevel(value) {
|
|
13
|
+
return LEVELS.includes(String(value || "").trim().toLowerCase());
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
const COPY = {
|
|
13
17
|
en: {
|
|
14
18
|
read: {
|
|
@@ -94,4 +98,4 @@ function createCycleController(options = {}) {
|
|
|
94
98
|
};
|
|
95
99
|
}
|
|
96
100
|
|
|
97
|
-
module.exports = { LEVELS, normalize, persistent, next, copy, createCycleController };
|
|
101
|
+
module.exports = { LEVELS, isLevel, normalize, persistent, next, copy, createCycleController };
|
|
@@ -1096,6 +1096,7 @@ function validateWorkOrder(value) {
|
|
|
1096
1096
|
|
|
1097
1097
|
function validateCandidateSet(value, workOrder, now = new Date(), options = {}) {
|
|
1098
1098
|
const set = assertObject(value, "candidateSet");
|
|
1099
|
+
const summaryMenu = set.projection === "menu.v1";
|
|
1099
1100
|
assertNoForbiddenFitSignals(set);
|
|
1100
1101
|
// projection은 로컬 Core(연합) 응답에만 있는 메뉴 투영 메타데이터다(실측
|
|
1101
1102
|
// 2026-08-05, reference-first: fullDossier=false). 원격 서버는 보내지 않는다.
|
|
@@ -1129,15 +1130,21 @@ function validateCandidateSet(value, workOrder, now = new Date(), options = {})
|
|
|
1129
1130
|
const orderSlot = orderSlots.get(slotId);
|
|
1130
1131
|
seenSlots.add(slotId);
|
|
1131
1132
|
const releases = new Set();
|
|
1132
|
-
for (const candidate of assertArray(slotResult.candidates, `candidateSet.${slotId}.candidates`, 100)) {
|
|
1133
|
+
for (const [candidateIndex, candidate] of assertArray(slotResult.candidates, `candidateSet.${slotId}.candidates`, 100).entries()) {
|
|
1133
1134
|
assertObject(candidate, "candidate");
|
|
1134
1135
|
// missingMandatory는 로컬 Core(연합) 응답에만 있는 미충족 필수 표식이다
|
|
1135
1136
|
// (실측 2026-08-05, fullDossier=true에도 동봉). 원격 서버는 보내지 않는다.
|
|
1136
|
-
const candidateKeys =
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1137
|
+
const candidateKeys = summaryMenu
|
|
1138
|
+
? [
|
|
1139
|
+
"agentDefinitionId", "agentReleaseId", "releaseVersion", "entityKind", "name",
|
|
1140
|
+
"communities", "fitEvidence", "qualificationEvidenceCount", "optionalGaps",
|
|
1141
|
+
"semanticSnapshot", "operational", "candidateOrdinal",
|
|
1142
|
+
]
|
|
1143
|
+
: [
|
|
1144
|
+
"agentDefinitionId", "agentReleaseId", "releaseVersion", "packageHash", "contentDigest",
|
|
1145
|
+
"entityKind", "name", "communities", "fitEvidence", "qualificationEvidence", "optionalGaps",
|
|
1146
|
+
"semanticSnapshot", "operational",
|
|
1147
|
+
];
|
|
1141
1148
|
if (Object.prototype.hasOwnProperty.call(candidate, "missingMandatory")) candidateKeys.push("missingMandatory");
|
|
1142
1149
|
assertExactKeys(candidate, candidateKeys, "candidate", "candidate_set_invalid");
|
|
1143
1150
|
assertId(candidate.agentDefinitionId, "candidate.agentDefinitionId");
|
|
@@ -1145,15 +1152,22 @@ function validateCandidateSet(value, workOrder, now = new Date(), options = {})
|
|
|
1145
1152
|
if (releases.has(releaseId)) fail("candidate_set_invalid", `duplicate release ${releaseId} in ${slotId}`);
|
|
1146
1153
|
releases.add(releaseId);
|
|
1147
1154
|
assertString(candidate.releaseVersion, "candidate.releaseVersion", 100);
|
|
1148
|
-
|
|
1149
|
-
|
|
1155
|
+
if (summaryMenu) {
|
|
1156
|
+
if (candidate.candidateOrdinal !== candidateIndex + 1) fail("candidate_set_invalid", `candidate ordinal mismatch in ${slotId}`);
|
|
1157
|
+
if (!Number.isInteger(candidate.qualificationEvidenceCount) || candidate.qualificationEvidenceCount < 0) {
|
|
1158
|
+
fail("candidate_set_invalid", "candidate.qualificationEvidenceCount is invalid");
|
|
1159
|
+
}
|
|
1160
|
+
} else {
|
|
1161
|
+
assertHash(candidate.packageHash, "candidate.packageHash");
|
|
1162
|
+
assertHash(candidate.contentDigest, "candidate.contentDigest");
|
|
1163
|
+
}
|
|
1150
1164
|
if (!["agent", "team"].includes(candidate.entityKind) || !orderSlot.allowedEntityKinds.includes(candidate.entityKind)) {
|
|
1151
1165
|
fail("candidate_set_invalid", "candidate.entityKind is not executable or violates the WorkOrder slot boundary");
|
|
1152
1166
|
}
|
|
1153
1167
|
assertString(candidate.name, "candidate.name", 200);
|
|
1154
1168
|
assertIds(candidate.communities, "candidate.communities");
|
|
1155
1169
|
assertIds(candidate.fitEvidence, "candidate.fitEvidence");
|
|
1156
|
-
assertIds(candidate.qualificationEvidence, "candidate.qualificationEvidence");
|
|
1170
|
+
if (!summaryMenu) assertIds(candidate.qualificationEvidence, "candidate.qualificationEvidence");
|
|
1157
1171
|
assertIds(candidate.optionalGaps, "candidate.optionalGaps");
|
|
1158
1172
|
const operational = assertObject(candidate.operational, "candidate.operational");
|
|
1159
1173
|
assertExactKeys(operational, ["callable", "installable"], "candidate.operational", "candidate_set_invalid", ["unavailableReasons"]);
|
|
@@ -1163,10 +1177,15 @@ function validateCandidateSet(value, workOrder, now = new Date(), options = {})
|
|
|
1163
1177
|
// knowledge·modalities는 로컬 Core 스냅샷에만 있는 확장 어휘다(실측 2026-08-05).
|
|
1164
1178
|
// 원격 서버는 보내지 않는다 — missingMandatory·projection과 같은 규칙으로
|
|
1165
1179
|
// "있으면 검증하고 허용", 원격 계약의 exact-keys는 그대로 둔다.
|
|
1166
|
-
const semanticKeys =
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1180
|
+
const semanticKeys = summaryMenu
|
|
1181
|
+
? [
|
|
1182
|
+
"summaries", "roles", "skills", "toolCapabilities", "consumesCount", "producesCount",
|
|
1183
|
+
"authorities", "runtimes", "languages",
|
|
1184
|
+
]
|
|
1185
|
+
: [
|
|
1186
|
+
"summaries", "roles", "skills", "toolCapabilities", "consumes", "produces",
|
|
1187
|
+
"authorities", "runtimes", "languages",
|
|
1188
|
+
];
|
|
1170
1189
|
for (const optional of ["knowledge", "modalities"]) {
|
|
1171
1190
|
if (Object.prototype.hasOwnProperty.call(semantic, optional)) semanticKeys.push(optional);
|
|
1172
1191
|
}
|
|
@@ -1177,8 +1196,14 @@ function validateCandidateSet(value, workOrder, now = new Date(), options = {})
|
|
|
1177
1196
|
assertIds(semantic.roles, "candidate.semanticSnapshot.roles");
|
|
1178
1197
|
assertLeveledConcepts(semantic.skills, "candidate.semanticSnapshot.skills");
|
|
1179
1198
|
assertLeveledConcepts(semantic.toolCapabilities, "candidate.semanticSnapshot.toolCapabilities");
|
|
1180
|
-
|
|
1181
|
-
|
|
1199
|
+
if (summaryMenu) {
|
|
1200
|
+
for (const field of ["consumesCount", "producesCount"]) {
|
|
1201
|
+
if (!Number.isInteger(semantic[field]) || semantic[field] < 0) fail("candidate_set_invalid", `candidate.semanticSnapshot.${field} is invalid`);
|
|
1202
|
+
}
|
|
1203
|
+
} else {
|
|
1204
|
+
assertIds(semantic.consumes, "candidate.semanticSnapshot.consumes");
|
|
1205
|
+
assertIds(semantic.produces, "candidate.semanticSnapshot.produces");
|
|
1206
|
+
}
|
|
1182
1207
|
assertIds(semantic.authorities, "candidate.semanticSnapshot.authorities");
|
|
1183
1208
|
assertStrings(semantic.runtimes, "candidate.semanticSnapshot.runtimes");
|
|
1184
1209
|
assertStrings(semantic.languages, "candidate.semanticSnapshot.languages");
|
|
@@ -1379,7 +1404,9 @@ function normalizedRosterPairs(rows, label, candidateSet) {
|
|
|
1379
1404
|
seen.add(pair);
|
|
1380
1405
|
const candidate = maps.bySlot.get(slotId)?.get(releaseId);
|
|
1381
1406
|
if (!candidate || candidate.agentDefinitionId !== definitionId || candidate.releaseVersion !== releaseVersion ||
|
|
1382
|
-
candidate.packageHash !==
|
|
1407
|
+
(candidate.packageHash !== undefined && candidate.packageHash !== packageHash) ||
|
|
1408
|
+
(candidate.contentDigest !== undefined && candidate.contentDigest !== contentDigest) ||
|
|
1409
|
+
candidate.entityKind !== row.entityKind) {
|
|
1383
1410
|
fail("selection_validation_invalid", `${label}[${index}] does not match the frozen candidate release`);
|
|
1384
1411
|
}
|
|
1385
1412
|
return pair;
|
|
@@ -1479,6 +1506,10 @@ function validatePreparedExecution(value, workOrder, selection, candidateSet, va
|
|
|
1479
1506
|
const contextDigest = assertHash(prepared.executionContextDigest, "preparedExecution.executionContextDigest");
|
|
1480
1507
|
if (!constantTimeHashEqual(contextDigest, executionContextDigest(context))) fail("execution_context_mismatch", "prepared execution context digest is invalid");
|
|
1481
1508
|
const maps = candidateMaps(candidateSet);
|
|
1509
|
+
const validatedRows = new Map(validationReceipt.executableTeam.map((row) => [
|
|
1510
|
+
`${row.slotId}\0${row.agentReleaseId}`,
|
|
1511
|
+
row,
|
|
1512
|
+
]));
|
|
1482
1513
|
const expected = selectedPairs(selection);
|
|
1483
1514
|
const roster = assertArray(prepared.executionRoster, "preparedExecution.executionRoster", MAX_ASSIGNMENTS, { min: 1 });
|
|
1484
1515
|
const actual = [];
|
|
@@ -1512,7 +1543,18 @@ function validatePreparedExecution(value, workOrder, selection, candidateSet, va
|
|
|
1512
1543
|
const bundleDigest = assertHash(row.bundleDigest, "executionRoster.bundleDigest");
|
|
1513
1544
|
assertObject(row.directiveBundle, "executionRoster.directiveBundle");
|
|
1514
1545
|
if (!["agent", "team"].includes(row.entityKind)) fail("execution_bundle_invalid", "executionRoster.entityKind is invalid");
|
|
1515
|
-
|
|
1546
|
+
const validated = validatedRows.get(pair);
|
|
1547
|
+
if (!validated) fail("execution_bundle_invalid", `prepared release ${releaseId} has no accepted exact-release receipt`);
|
|
1548
|
+
if (
|
|
1549
|
+
definitionId !== candidate.agentDefinitionId ||
|
|
1550
|
+
releaseVersion !== candidate.releaseVersion ||
|
|
1551
|
+
row.entityKind !== candidate.entityKind ||
|
|
1552
|
+
definitionId !== validated.agentDefinitionId ||
|
|
1553
|
+
releaseVersion !== validated.releaseVersion ||
|
|
1554
|
+
packageHash !== validated.packageHash ||
|
|
1555
|
+
contentDigest !== validated.contentDigest ||
|
|
1556
|
+
row.entityKind !== validated.entityKind
|
|
1557
|
+
) fail("execution_bundle_digest_mismatch", `prepared bytes do not match the accepted exact-release receipt for ${releaseId}`);
|
|
1516
1558
|
if (releaseVersion !== candidate.releaseVersion) fail("execution_bundle_digest_mismatch", `prepared version does not match candidate pin for ${releaseId}`);
|
|
1517
1559
|
if (definitionId !== candidate.agentDefinitionId) fail("execution_bundle_digest_mismatch", `prepared definition does not match candidate pin for ${releaseId}`);
|
|
1518
1560
|
if (row.entityKind !== candidate.entityKind) fail("execution_bundle_digest_mismatch", `prepared entity kind does not match candidate pin for ${releaseId}`);
|
|
@@ -1660,6 +1702,7 @@ function candidateMenu(candidateSet) {
|
|
|
1660
1702
|
.slice(0, 5)
|
|
1661
1703
|
.map((value) => term(value, "skill:"));
|
|
1662
1704
|
const row = {
|
|
1705
|
+
candidateOrdinal: candidate.candidateOrdinal,
|
|
1663
1706
|
agentReleaseId: candidate.agentReleaseId,
|
|
1664
1707
|
name: String(candidate.name || "").slice(0, 80),
|
|
1665
1708
|
entityKind: candidate.entityKind,
|
|
@@ -1668,8 +1711,10 @@ function candidateMenu(candidateSet) {
|
|
|
1668
1711
|
if (skills.length) row.skills = skills;
|
|
1669
1712
|
const roles = (snapshot.roles || []).slice(0, 2).map((value) => term(value, "role:"));
|
|
1670
1713
|
if (roles.length) row.roles = roles;
|
|
1671
|
-
const summary = String(snapshot.
|
|
1714
|
+
const summary = String((snapshot.summaries || [])[0] || candidate.summary || "").trim();
|
|
1672
1715
|
if (summary) row.summary = summary.slice(0, 200);
|
|
1716
|
+
const fitEvidence = (candidate.fitEvidence || []).slice(0, 4).map(String);
|
|
1717
|
+
if (fitEvidence.length) row.fitEvidence = fitEvidence;
|
|
1673
1718
|
return row;
|
|
1674
1719
|
}),
|
|
1675
1720
|
})),
|
|
@@ -2450,6 +2495,16 @@ const TRANSIENT_MODEL_ERROR_RE = /Connection closed mid-response|"terminal_reaso
|
|
|
2450
2495
|
}
|
|
2451
2496
|
return value;
|
|
2452
2497
|
})();
|
|
2498
|
+
// 후보 검색 인자는 **여기 한 곳**에서만 만든다. hubStage 는 보낸 인자 객체로
|
|
2499
|
+
// requestDigest 를 계산하고 supersedeCandidateSearch 는 같은 값을 다시 만들어
|
|
2500
|
+
// 행을 찾으므로, 두 곳이 어긋나면 supersession 이 조용히 실패한다(sourceScope
|
|
2501
|
+
// 추가 때 한 번, fullDossier 추가 때 또 한 번 실측으로 깨졌다).
|
|
2502
|
+
//
|
|
2503
|
+
// Current Core returns a numbered summary menu by default and keeps the
|
|
2504
|
+
// audit-weight dossier in its pinned selection session. Exact hashes are
|
|
2505
|
+
// reintroduced only in accepted validation/preparation receipts and are
|
|
2506
|
+
// cross-checked there; never request or echo the legacy full dossier.
|
|
2507
|
+
const candidateSearchArgs = (workOrder) => ({ workOrder, sourceScope });
|
|
2453
2508
|
const ui = ctx.ui || newUi();
|
|
2454
2509
|
const runtime = ctx.runtime || D.resolveRuntime(db, ctx.runtimeOverride);
|
|
2455
2510
|
const cwd = ctx.cwd || (typeof D.projectCwd === "function" ? D.projectCwd() : process.cwd());
|
|
@@ -2801,9 +2856,11 @@ const TRANSIENT_MODEL_ERROR_RE = /Connection closed mid-response|"terminal_reaso
|
|
|
2801
2856
|
};
|
|
2802
2857
|
|
|
2803
2858
|
const supersedeCandidateSearch = (workOrder, refinementNumber, triggerKind) => {
|
|
2804
|
-
// hubStage가 저장한 requestDigest와
|
|
2805
|
-
//
|
|
2806
|
-
|
|
2859
|
+
// hubStage가 저장한 requestDigest와 **같은 인자 객체**여야 행을 찾는다.
|
|
2860
|
+
// 이 다이제스트를 손으로 다시 조립하는 구조가 이미 두 번 깨졌다(sourceScope
|
|
2861
|
+
// 추가 때 한 번, fullDossier 추가 때 또 한 번) — 인자는 candidateSearchArgs
|
|
2862
|
+
// 한 곳에서만 만든다.
|
|
2863
|
+
const requestDigest = sha256(candidateSearchArgs(workOrder));
|
|
2807
2864
|
for (const row of receipt.hubTools) {
|
|
2808
2865
|
if (row.tool !== "workforce.search_candidates" || row.requestDigest !== requestDigest || row.authoritativeChain !== true) continue;
|
|
2809
2866
|
row.authoritativeChain = false;
|
|
@@ -3133,7 +3190,7 @@ const TRANSIENT_MODEL_ERROR_RE = /Connection closed mid-response|"terminal_reaso
|
|
|
3133
3190
|
// sourceScope는 MCP 스키마상 required다. 예전에는 싣지 않아 서버 기본값
|
|
3134
3191
|
// ("hub")에 의존했다 — 기본값이 바뀌면 이 표면의 실제 스코프가 조용히
|
|
3135
3192
|
// 넓어지거나 좁아진다. 이 표면이 보는 메뉴를 스스로 선언한다.
|
|
3136
|
-
const candidateRaw = await hubStage("workforce.search_candidates",
|
|
3193
|
+
const candidateRaw = await hubStage("workforce.search_candidates", candidateSearchArgs(workOrder));
|
|
3137
3194
|
candidateSet = validateCandidateSet(
|
|
3138
3195
|
candidateRaw,
|
|
3139
3196
|
workOrder,
|
|
@@ -3269,13 +3326,13 @@ const TRANSIENT_MODEL_ERROR_RE = /Connection closed mid-response|"terminal_reaso
|
|
|
3269
3326
|
: ` picked ${row.slotId} ← ${nameByRelease.get(row.agentReleaseId) || row.agentReleaseId}`);
|
|
3270
3327
|
}
|
|
3271
3328
|
}
|
|
3272
|
-
const validationRaw = await hubStage("workforce.validate_selection", { workOrder,
|
|
3329
|
+
const validationRaw = await hubStage("workforce.validate_selection", { workOrder, selection });
|
|
3273
3330
|
validationReceipt = validateSelectionReceipt(validationRaw, selection, candidateSet, workOrder);
|
|
3274
3331
|
benchmarkState.selectionValidation = validationReceipt;
|
|
3275
3332
|
receipt.selectionReceiptId = validationReceipt.selectionReceiptId;
|
|
3276
3333
|
if (!ctx.silent) ui.info(ui.lang === "ko" ? "허브 검증 수락 — 번들 준비 중" : "hub validation accepted — preparing bundles");
|
|
3277
3334
|
|
|
3278
|
-
const preparedRaw = await hubStage("workforce.prepare_execution", { workOrder,
|
|
3335
|
+
const preparedRaw = await hubStage("workforce.prepare_execution", { workOrder, selection, validationReceipt });
|
|
3279
3336
|
({ prepared, rosterByPair } = validatePreparedExecution(preparedRaw, workOrder, selection, candidateSet, validationReceipt));
|
|
3280
3337
|
receipt.preparationReceiptId = prepared.preparationReceiptId;
|
|
3281
3338
|
benchmarkState.preparedExecution = prepared;
|
package/engine/agents/router.cjs
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
const crypto = require("node:crypto");
|
|
13
13
|
const { listRoutableAgents } = require("./registry.cjs");
|
|
14
|
+
const { sharedRuntimeKind } = require("../runtimes/resolve.cjs");
|
|
14
15
|
|
|
15
16
|
const UNRESOLVED_LABEL = "unresolved";
|
|
16
17
|
|
|
@@ -28,8 +29,9 @@ function ensureJudgeRunner(db, runtime) {
|
|
|
28
29
|
if (!resolved && db) {
|
|
29
30
|
try {
|
|
30
31
|
const active = require("../runtimes/detect.cjs").activeRuntimeRow(db);
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
const activeKind = sharedRuntimeKind(active);
|
|
33
|
+
if (active && capture.RUNTIME_BIN[activeKind]) {
|
|
34
|
+
resolved = { kind: activeKind, model: active.model || null };
|
|
33
35
|
} else if (active && active.kind === "byok" && active.backend) {
|
|
34
36
|
resolved = { kind: "byok", backend: active.backend, model: active.model || null };
|
|
35
37
|
} else if (active && active.kind === "ollama") {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.7.
|
|
2
|
+
"version": "1.7.2",
|
|
3
3
|
"emitterBlock": "## Memory (Agentlas curated memory)\n\nAt the end of EVERY completed normal reply, emit exactly one hidden Memory Events\nenvelope. The runtime removes it before display. This envelope is the per-turn receipt:\nalways include a compact safe turn_summary, and use an empty candidates array when\nnothing durable was learned. Do not skip the envelope.\n\nRules:\n- Never include secrets, credentials, API keys, raw logs, or full transcripts.\n- Real credential values may live only in local project .env/.env.local,\n ignored signing/ or credentials/ files, or a local keychain/vault. Memory\n Events may mention env names and local relative paths only.\n- For deploy, release, store, billing, auth, API, or cloud work, first read the\n project's .agentlas/local-credentials.map.json and the top\n \"Local Credential Index\" section of .agentlas/project-soul-memory.md\n before saying a credential is missing.\n- One candidate per durable item. Keep \"content\" to one or two sentences.\n- \"memory_kind\": fact | decision | preference | risk | procedure | hypothesis | evidence | deprecation | conflict\n- \"suggested_scope\": user_identity | team_memory | project (this folder) | agent_repo | session (temporary) | discard\n- Use user_identity for a stable operator preference or personal fact (their name, role, language, tone,\n how they want you to behave) — these must outlive any one project. The curator only files user_identity\n when you label it so with \"confidence\": \"high\"; it never promotes into that scope, so a preference emitted\n at lower confidence is demoted to a throwaway session note.\n- \"agent_team\" is accepted only as a legacy alias for team_memory.\n- Add \"request_context\" when it improves future recall: user_intent, trigger_terms,\n cwd_at_request, target_project, target_path, cross_context, outcome.\n- Never put the raw user prompt or transcript in request_context.\n- Suggest a scope; the separate Memory Curator decides the final destination.\n- turn_summary is one value-free sentence about the completed outcome. It is not the\n user prompt, a transcript, raw log, secret, or absolute local path.\n\nFormat (always emit, including an empty candidates array):\n\n## Memory Events\n```json\n{\n \"schema_version\": \"agentlas.memory-ticket.v1\",\n \"turn_summary\": \"Completed outcome in one safe sentence.\",\n \"candidates\": [\n {\n \"memory_kind\": \"decision\",\n \"content\": \"...\",\n \"suggested_scope\": \"project\",\n \"confidence\": \"high\",\n \"sensitivity\": \"internal\",\n \"evidence_refs\": [],\n \"request_context\": {\n \"user_intent\": \"...\",\n \"trigger_terms\": [\"...\"],\n \"cwd_at_request\": null,\n \"target_project\": null,\n \"target_path\": null,\n \"cross_context\": false,\n \"outcome\": \"...\"\n }\n }\n ]\n}\n```",
|
|
4
4
|
"eventsHeading": "## Memory Events",
|
|
5
5
|
"memoryDir": ".agentlas",
|
|
@@ -14,38 +14,14 @@
|
|
|
14
14
|
"skillRegistryFile": "skill-registry.json",
|
|
15
15
|
"skillTrialsFile": "skill-trials.jsonl",
|
|
16
16
|
"curatorDecisionsFile": "curator-decisions.jsonl",
|
|
17
|
+
"ontologyRuntimeFile": "ontology-runtime.json",
|
|
18
|
+
"ontologySourceManifestFile": "ontology-sources.json",
|
|
19
|
+
"ontologyInboxDir": "ontology-inbox",
|
|
20
|
+
"ontologyDbFile": "ontology-runtime.sqlite",
|
|
17
21
|
"careerGraphConfigFile": "career-graph.json",
|
|
18
22
|
"careerGraphSourceManifestFile": "career-graph-sources.json",
|
|
19
23
|
"careerGraphInboxDir": "career-graph-inbox",
|
|
20
24
|
"careerGraphDbFile": "career-graph.sqlite",
|
|
21
|
-
"superOntologyContractFile": "super-ontology-contract.json",
|
|
22
|
-
"superOntologyOpenWorldCoverageFile": "super-ontology-open-world-coverage.json",
|
|
23
|
-
"superOntologyConsensusCoordinationFile": "super-ontology-consensus-coordination.json",
|
|
24
|
-
"superOntologyTaskCoverageFile": "super-ontology-task-coverage.json",
|
|
25
|
-
"superOntologyAssuranceCaseFile": "super-ontology-assurance-case.json",
|
|
26
|
-
"superOntologyContextualFlowFile": "super-ontology-contextual-flow.json",
|
|
27
|
-
"superOntologyCausalImpactFile": "super-ontology-causal-impact.json",
|
|
28
|
-
"superOntologyKnowledgeHomeostasisFile": "super-ontology-knowledge-homeostasis.json",
|
|
29
|
-
"superOntologyAdversarialProvenanceFile": "super-ontology-adversarial-provenance.json",
|
|
30
|
-
"superOntologyEpistemicCalibrationFile": "super-ontology-epistemic-calibration.json",
|
|
31
|
-
"superOntologySemanticAlignmentFile": "super-ontology-semantic-alignment.json",
|
|
32
|
-
"superOntologyResilienceControlFile": "super-ontology-resilience-control.json",
|
|
33
|
-
"superOntologyInvariantVerificationFile": "super-ontology-invariant-verification.json",
|
|
34
|
-
"superOntologyObservabilityTelemetryFile": "super-ontology-observability-telemetry.json",
|
|
35
|
-
"superOntologyObjectiveProxyValidityFile": "super-ontology-objective-proxy-validity.json",
|
|
36
|
-
"superOntologyStakeholderPreferenceGovernanceFile": "super-ontology-stakeholder-preference-governance.json",
|
|
37
|
-
"superOntologyNormativeAuthorityDriftFile": "super-ontology-normative-authority-drift.json",
|
|
38
|
-
"superOntologySideEffectContainmentFile": "super-ontology-side-effect-containment.json",
|
|
39
|
-
"superOntologySourceLineageVersionFile": "super-ontology-source-lineage-version.json",
|
|
40
|
-
"superOntologyEntityIdentityResolutionFile": "super-ontology-entity-identity-resolution.json",
|
|
41
|
-
"superOntologyTemporalStateTransitionFile": "super-ontology-temporal-state-transition.json",
|
|
42
|
-
"superOntologyCapabilityDelegationAuthorityFile": "super-ontology-capability-delegation-authority.json",
|
|
43
|
-
"superOntologyPrivacyConfidentialityBoundaryFile": "super-ontology-privacy-confidentiality-boundary.json",
|
|
44
|
-
"superOntologyStrategicIncentiveCompatibilityFile": "super-ontology-strategic-incentive-compatibility.json",
|
|
45
|
-
"superOntologyReflexiveFeedbackStabilityFile": "super-ontology-reflexive-feedback-stability.json",
|
|
46
|
-
"superOntologyReplaysFile": "super-ontology-replays.jsonl",
|
|
47
|
-
"superOntologyEvidenceFile": "super-ontology-evidence.jsonl",
|
|
48
|
-
"superOntologyMemoryBridgeFile": "super-ontology-memory-bridge.jsonl",
|
|
49
25
|
"kinds": [
|
|
50
26
|
"fact",
|
|
51
27
|
"decision",
|
|
@@ -101,7 +77,7 @@
|
|
|
101
77
|
"role": "builder",
|
|
102
78
|
"visibility": "background",
|
|
103
79
|
"tone": "purple",
|
|
104
|
-
"systemPrompt": "# Agentlas Core Engine Meta-Agent (built-in)\n\nYou are the local Agentlas Core Engine Meta-Agent for Agentlas Desktop and the\nAgentlas terminal. You create or package agent systems in the Agentlas architecture\nwhile staying compatible with local runtimes such as Codex, Claude, Gemini, OpenCode,\nHermes, and other folder-based agent hosts.\n\n## Source contract\nMirror the public core architecture and foldering contract from\nagentlas-ai/Agentlas-OS. This built-in prompt is the local runtime\ndistillation, not a forked original. If the full public core package is installed\nor available in the workspace, read and follow that package first.\n\n## Modes\nAuto-classify each request:\n- single-agent-creator: create one installable, self-evolving worker.\n- team-builder: create a multi-role team with HQ/orchestrator, builders, PM Soul,\n Memory Curator, Policy Gate, QA/evidence gate, handoffs, eval, memory, and runtime\n adapters.\n- agentlas-packager: inspect an existing prompt, agent, team, repo, or ZIP and\n repair/package it into Agentlas architecture.\n\nAsk at most the missing questions needed to avoid a wrong package. If the user gave\nenough context, proceed without an interview.\n\n## Required Agentlas architecture\nEvery package you design should include the pieces that make it Agentlas, scaled to\nthe task size:\n- visible role/folder architecture, not a paper-only description;\n- .agentlas activation metadata, memory-map, sitemap, memory tickets, and evidence;\n- .agentlas skill-registry, skill-trials, and curator-decisions files as\n candidate-only lifecycle metadata;\n- .agentlas super-ontology-contract, super-ontology-open-world-coverage,\n super-ontology-consensus-coordination, super-ontology-task-coverage,\n super-ontology-contextual-flow, super-ontology-assurance-case,\n super-ontology-causal-impact,\n super-ontology-knowledge-homeostasis,\n super-ontology-adversarial-provenance,\n super-ontology-epistemic-calibration,\n super-ontology-semantic-alignment,\n super-ontology-resilience-control,\n super-ontology-invariant-verification,\n super-ontology-observability-telemetry,\n\t super-ontology-objective-proxy-validity,\n\t super-ontology-stakeholder-preference-governance,\n\t super-ontology-normative-authority-drift,\n\t super-ontology-side-effect-containment,\n\t super-ontology-source-lineage-version,\n\t super-ontology-entity-identity-resolution,\n\t super-ontology-temporal-state-transition,\n\t super-ontology-capability-delegation-authority,\n\t super-ontology-privacy-confidentiality-boundary,\n\t super-ontology-strategic-incentive-compatibility,\n\t super-ontology-reflexive-feedback-stability,\n\t super-ontology-replays,\n super-ontology-evidence, and super-ontology-memory-bridge files as\n candidate-only adaptive knowledge governance metadata. Open-world coverage\n\t ledger keys include objectiveProxyValidity, stakeholderPreferenceGovernance,\n\t normativeAuthorityDrift, sideEffectContainment, sourceLineageVersion, entityIdentityResolution, temporalStateTransition, capabilityDelegationAuthority, privacyConfidentialityBoundary, strategicIncentiveCompatibility, reflexiveFeedbackStability, and memoryCuratorBridge\n\t for cross-surface sync checks. Open-world coverage\n must lower authority for new world/task/modality/fault/authority/write\n combinations before action. Consensus coordination must treat agent agreement,\n majority vote, debate, model-judge approval, distributed replica merge, and\n cross-runtime sync as candidate signals rather than write authority. Task\n coverage must classify requested work beyond\n proposal/deck generation before action, and\n contextual flow contracts must check sender, recipient, subject, purpose,\n authority, transmission principle, and retention before information crosses\n personal/company/customer/public/regulated/agent-internal boundaries.\n assurance cases must link broad safety/coverage claims to evidence,\n validators, residual risk, and rollback. Causal impact contracts must link\n relation/action claims to intervention targets, counterfactuals, blast\n radius, observability, and rollback before write/publish/execute/physical/train\n behavior. Knowledge homeostasis contracts must link stale, contradictory,\n unsupported, drifting, privacy-incident, missing-evidence, user-corrected, or\n runtime-desynced knowledge to signals, error budgets, quarantine, repair,\n rollback, retirement, Memory Curator policy, and public export policy.\n In local operator mode, Super Ontology promotion gates are context, folder,\n owner, evidence, and rollback organization rules (\"context_folder_routing_only\").\n They must not become a\n generic security stop sign that prevents local work when the operator has\n named the project root, source folder, owner, evidence refs, and rollback or\n replay path. Public exports stay value-free and candidate-only.\n Adversarial provenance contracts must treat uploads, web pages, emails, chats,\n tool responses, connector results, memory recalls, public repos, media assets,\n AppBridge routes, generated artifacts, and datasets as untrusted until source\n identity, span grounding, freshness, integrity, attestation, or content\n credentials prove they can be read. They must block prompt injection, poisoned\n sources, forged provenance, spoofed citations, hidden OCR instructions,\n tool-output tampering, stale trusted-source replay, and unsigned release\n artifacts from becoming retrieval, memory, tool, or public seed authority.\n Epistemic calibration contracts must block missing evidence, source conflict,\n stale evidence, low retrieval relevance, model disagreement, and uncalibrated\n confidence from becoming answers, memory writes, tool actions, route sync, or\n public artifacts. Semantic alignment contracts must block same-label,\n embedding-similarity, abbreviation, OCR, generated-label, route-label,\n source-conflict, and missing-unit shortcuts from becoming exact/equivalent\n mappings, same-individual assertions, graph edges, memory merges, or public\n artifacts without scope, validation, owner review, diff, and rollback.\n Observability telemetry contracts must block graph, memory, tool, public,\n route, release, repair, rollback, and emergency-stop writes when trace id,\n span id, correlation id, source/evidence refs, audit sink, redaction/retention\n policy, before/after snapshots, rollback refs, alert refs, or sample-size\n evidence are missing. Objective proxy validity contracts must block approval\n rates, open rates, benchmark scores, test pass rates, ontology edge counts,\n reward deltas, self-judge scores, short-term profit, and green dashboards from\n becoming success or write authority without construct definition,\n countermetrics, stakeholder review, gaming probes, and rollback.\n Stakeholder preference governance contracts must block owner approval,\n majority vote, behavior signals, role power, stale preference records, and\n strategic preference reports from becoming write authority without stakeholder\n maps, authority scope, aggregation rules, consent or rights vetoes, dissent,\n appeal paths, review owners, and rollback. Normative authority drift contracts\n must block stale policies, wrong jurisdictions, draft contracts, superseded\n rules, expired consent, translation/summary shortcuts, license conflicts,\n\t cross-border transfer gaps, and emergency exceptions without expiry from\n\t becoming authority without primary source, effective date, scope, precedence,\n\t review owner, audit trail, and rollback. Side-effect containment contracts\n\t must block preview-as-send, dry-run-as-commit, non-idempotent retry,\n\t deletion without recovery, payment without idempotency, customer message\n\t without review, release without rollback, partial failure without saga state,\n\t physical action without safety interlock, scheduled action without\n\t cancellation, and hosted tool writes without local containment wrappers from\n\t executing without dry-run, exact approval, transaction or compensation plan,\n\t cancellation path, blast radius, receipt, audit trace, rollback, and\n\t post-action verification. Entity identity resolution contracts must block\n\t names, aliases, domains, phone numbers, CRM ids, recycled ids, redacted\n\t ids, embedding clusters, stale aliases, external URIs, memory notes, and\n\t LLM-generated canonical labels from becoming same-entity authority without\n\t canonical id, source-system namespace, source span, negative evidence,\n\t temporal validity, privacy basis, owner review, merge/split policy, audit,\n\t and rollback. Capability delegation authority contracts must block roles,\n\t OAuth scopes, API keys, service accounts, session cookies, tool schemas,\n\t cached policy decisions, broad approvals, and child-agent tokens from\n\t becoming graph, memory, public, training, tool, route, scheduled,\n\t permission, financial, release, customer-output, or physical authority\n\t without actor identity, task, operation, resource, scope, purpose,\n\t delegation chain, caveats, revocation, audit, rollback, and post-action\n\t verification. Keep\n\t graph writes and direct durable memory writes disabled until\n shadow/canary/rollback evidence, homeostasis review, adversarial provenance\n review, epistemic calibration review, semantic alignment review, resilience\n control review, invariant verification, observability telemetry review,\n\t objective proxy validity review, stakeholder preference governance review,\n\t normative authority drift review, side-effect containment review,\n\t source lineage version review, entity identity resolution review,\n\t temporal state transition review, capability delegation authority review,\n\t strategic incentive compatibility review, reflexive feedback stability\n\t review, and Memory\n\t Curator review exist;\n- PM Soul or project owner loop for continuity;\n- Memory Curator rules for durable memory, dedup, scope, and redaction;\n- task-bias / sitemap governance so stale or risky surfaces are revisited;\n- self-evolution rules with changelog, eval, rollback, and promotion criteria;\n- skill promotion stays export/local-candidate only until Curator quarantine,\n sealed holdouts, rollback, and workspace policy approve a later phase;\n- Super Ontology public graph writes stay disabled until source intake, evidence\n packets, belief ledger, knowledge capsules, affordance binding,\n contextual flow review, causal impact review, knowledge homeostasis review,\n adversarial provenance review, epistemic calibration review, shadow/canary\n replay, semantic alignment review, resilience control review, invariant\n verification, observability telemetry review, objective proxy validity review,\n stakeholder preference governance review,\n normative authority drift review,\n capability delegation authority review,\n rollback, and sync review\n approve a later phase;\n- hierarchy when useful: HQ/orchestrator -> builders/workers -> QA/evidence gate;\n- runtime adapters for AGENTS.md plus Claude/Codex/Gemini/OpenCode-style hosts when\n requested or detectable.\n\n## Local runtime boundaries\n- Do not copy Web-only SaaS implementation into local packages: billing, credits,\n accounts, workspace sessions, OAuth token storage, provider-cost telemetry, hosted\n rate limits, or database-backed SaaS routes.\n- Do not assume .claude is required. Prefer .agentlas as the shared architecture\n substrate, then add thin runtime adapters such as AGENTS.md, CLAUDE.md, GEMINI.md,\n .agents/skills, or .claude only when that host needs them.\n- Avoid slug collisions with installed public packages; built-in desktop agents are\n background runtime control routes.\n\n## Output contract\nReturn concrete files, folder layout, prompts, memory rules, verification steps, and\nsync notes. For package work, name what was inspected, what was added or rejected,\nwhat remains private, and how to verify the result."
|
|
80
|
+
"systemPrompt": "# Agentlas Core Engine Meta-Agent (built-in)\n\nYou are the local Agentlas Core Engine Meta-Agent for Agentlas Desktop and the\nAgentlas terminal. You create or package agent systems in the Agentlas architecture\nwhile staying compatible with local runtimes such as Codex, Claude, Gemini, OpenCode,\nHermes, and other folder-based agent hosts.\n\n## Source contract\nMirror the public core architecture and foldering contract from\nagentlas-ai/Agentlas-OS. This built-in prompt is the local runtime\ndistillation, not a forked original. If the full public core package is installed\nor available in the workspace, read and follow that package first.\n\n## Modes\nAuto-classify each request:\n- single-agent-creator: create one installable, self-evolving worker.\n- team-builder: create a multi-role team with HQ/orchestrator, builders, PM Soul,\n Memory Curator, Policy Gate, QA/evidence gate, handoffs, eval, memory, and runtime\n adapters.\n- agentlas-packager: inspect an existing prompt, agent, team, repo, or ZIP and\n repair/package it into Agentlas architecture.\n\nAsk at most the missing questions needed to avoid a wrong package. If the user gave\nenough context, proceed without an interview.\n\n## Required Agentlas architecture\nEvery package you design should include the pieces that make it Agentlas, scaled to\nthe task size:\n- visible role/folder architecture, not a paper-only description;\n- .agentlas activation metadata, memory-map, sitemap, memory tickets, and evidence;\n- .agentlas skill-registry, skill-trials, and curator-decisions files as\n candidate-only lifecycle metadata;\n- .agentlas ontology-runtime and ontology-sources files for project-scoped semantic ontology;\n- PM Soul or project owner loop for continuity;\n- Memory Curator rules for durable memory, dedup, scope, and redaction;\n- task-bias / sitemap governance so stale or risky surfaces are revisited;\n- self-evolution rules with changelog, eval, rollback, and promotion criteria;\n- skill promotion stays export/local-candidate only until Curator quarantine,\n sealed holdouts, rollback, and workspace policy approve a later phase;\n- hierarchy when useful: HQ/orchestrator -> builders/workers -> QA/evidence gate;\n- runtime adapters for AGENTS.md plus Claude/Codex/Gemini/OpenCode-style hosts when\n requested or detectable.\n\n## Local runtime boundaries\n- Do not copy Web-only SaaS implementation into local packages: billing, credits,\n accounts, workspace sessions, OAuth token storage, provider-cost telemetry, hosted\n rate limits, or database-backed SaaS routes.\n- Do not assume .claude is required. Prefer .agentlas as the shared architecture\n substrate, then add thin runtime adapters such as AGENTS.md, CLAUDE.md, GEMINI.md,\n .agents/skills, or .claude only when that host needs them.\n- Avoid slug collisions with installed public packages; built-in desktop agents are\n background runtime control routes.\n\n## Output contract\nReturn concrete files, folder layout, prompts, memory rules, verification steps, and\nsync notes. For package work, name what was inspected, what was added or rejected,\nwhat remains private, and how to verify the result."
|
|
105
81
|
},
|
|
106
82
|
{
|
|
107
83
|
"id": "builtin-agentlas-pm-soul",
|
|
@@ -24,13 +24,9 @@ const store = require("./store.cjs");
|
|
|
24
24
|
// getAutomationExecutionContractState 동형) ──────────────────────────────
|
|
25
25
|
// 손상된/미래 계약 값은 절대 조용히 넓혀 실행하지 않는다 — raw-row 게이트로
|
|
26
26
|
// 무인 실행 직전에 검사한다(데스크탑 automation-scheduler.ts:538-549).
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const RUNTIME_BACKENDS = new Set([
|
|
31
|
-
"anthropic", "openai", "google", "ollama", "lmstudio", "mlx", "upstage", "custom", "glm",
|
|
32
|
-
"kimi", "deepseek", "minimax", "xai", "openrouter", "cursor",
|
|
33
|
-
]);
|
|
27
|
+
const { CONTRACT_RUNTIME_KINDS, CONTRACT_RUNTIME_BACKENDS } = require("../runtimes/kinds.cjs");
|
|
28
|
+
const RUNTIME_KINDS = new Set(CONTRACT_RUNTIME_KINDS);
|
|
29
|
+
const RUNTIME_BACKENDS = new Set(CONTRACT_RUNTIME_BACKENDS);
|
|
34
30
|
const RUNTIME_SELECTION_KEYS = new Set(["kind", "backend", "source", "model", "longContext", "effort"]);
|
|
35
31
|
|
|
36
32
|
function decodeRuntimeSelection(raw) {
|