agentlas 1.0.65 → 1.0.67
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 +94 -0
- package/README.md +12 -4
- package/bin/agentlas.cjs +354 -16
- package/engine/acp/server.cjs +34 -3
- package/engine/agentlas-api-agent.cjs +151 -120
- package/engine/agentlas-banner.cjs +6 -2
- package/engine/agentlas-capabilities.cjs +17 -10
- package/engine/agentlas-cloud-runtime.cjs +4 -5
- package/engine/agentlas-config.cjs +19 -54
- package/engine/agentlas-core-harness.cjs +59 -5
- package/engine/agentlas-desktop-loadout.cjs +17 -3
- package/engine/agentlas-evolution.cjs +75 -18
- package/engine/agentlas-experience-exchange.cjs +145 -14
- package/engine/agentlas-experience-intake.cjs +2 -2
- package/engine/agentlas-i18n.cjs +0 -2
- package/engine/agentlas-input.cjs +273 -20
- package/engine/agentlas-judgment.cjs +0 -0
- package/engine/agentlas-mcp-env.cjs +84 -23
- package/engine/agentlas-mcp-wrapper.cjs +36 -4
- package/engine/agentlas-memory-governance.cjs +2 -1
- package/engine/agentlas-memory-import.cjs +49 -12
- package/engine/agentlas-native-host.cjs +279 -44
- package/engine/agentlas-onboard.cjs +23 -1
- package/engine/agentlas-permissions.cjs +5 -1
- package/engine/agentlas-sqlite-policy.cjs +40 -2
- package/engine/agentlas-tasks.cjs +7 -0
- package/engine/agentlas-tools.cjs +37 -10
- package/engine/agentlas-ui.cjs +26 -4
- package/engine/agentlas-workforce.cjs +30 -5
- package/engine/agentlas-workload-routing.cjs +83 -10
- package/engine/agentlas.cjs +21 -4
- package/engine/agents/builder.cjs +35 -10
- package/engine/agents/files.cjs +81 -10
- package/engine/agents/import-local.cjs +10 -2
- package/engine/agents/registry.cjs +10 -3
- package/engine/agents/router.cjs +7 -7
- package/engine/agents/routes.cjs +31 -9
- package/engine/automation/daemon.cjs +154 -40
- package/engine/automation/launchd.cjs +395 -16
- package/engine/automation/schedule.cjs +90 -3
- package/engine/automation/store.cjs +163 -59
- package/engine/browser/cdp.cjs +190 -17
- package/engine/browser/vault.cjs +1 -0
- package/engine/cli-output.cjs +96 -30
- package/engine/cloud/auth.cjs +131 -13
- package/engine/cloud/hub-client.cjs +41 -16
- package/engine/cloud-assets/cas.cjs +18 -9
- package/engine/cloud-assets/commands.cjs +108 -30
- package/engine/cloud-assets/package.cjs +66 -3
- package/engine/cloud-assets/restore.cjs +12 -9
- package/engine/cloud-assets/state.cjs +609 -116
- package/engine/commands/acp.cjs +13 -2
- package/engine/commands/automation.cjs +75 -24
- package/engine/commands/billing.cjs +6 -1
- package/engine/commands/browser.cjs +61 -29
- package/engine/commands/build.cjs +72 -14
- package/engine/commands/call.cjs +1 -1
- package/engine/commands/cd.cjs +1 -1
- package/engine/commands/cloud.cjs +2 -1
- package/engine/commands/connect.cjs +38 -13
- package/engine/commands/creds.cjs +74 -29
- package/engine/commands/doctor.cjs +17 -1
- package/engine/commands/document.cjs +38 -10
- package/engine/commands/env.cjs +6 -1
- package/engine/commands/firm.cjs +42 -12
- package/engine/commands/graph.cjs +36 -32
- package/engine/commands/help.cjs +11 -1
- package/engine/commands/hep.cjs +1 -1
- package/engine/commands/import.cjs +5 -4
- package/engine/commands/index.cjs +1 -1
- package/engine/commands/install.cjs +6 -4
- package/engine/commands/list.cjs +56 -16
- package/engine/commands/login.cjs +5 -0
- package/engine/commands/logout.cjs +6 -1
- package/engine/commands/mcp.cjs +150 -37
- package/engine/commands/memory.cjs +3 -2
- package/engine/commands/multimodal.cjs +12 -0
- package/engine/commands/native.cjs +5 -1
- package/engine/commands/one.cjs +78 -33
- package/engine/commands/plugin.cjs +13 -2
- package/engine/commands/project.cjs +15 -12
- package/engine/commands/research.cjs +18 -7
- package/engine/commands/roles.cjs +104 -28
- package/engine/commands/route.cjs +2 -2
- package/engine/commands/run.cjs +42 -9
- package/engine/commands/search.cjs +23 -2
- package/engine/commands/setup.cjs +6 -1
- package/engine/commands/storm.cjs +44 -6
- package/engine/commands/swarm.cjs +47 -9
- package/engine/commands/telegram.cjs +6 -1
- package/engine/commands/uninstall.cjs +12 -6
- package/engine/commands/update.cjs +5 -0
- package/engine/commands/upload.cjs +2 -1
- package/engine/commands/usage.cjs +6 -1
- package/engine/commands/version.cjs +6 -1
- package/engine/commands/whoami.cjs +6 -1
- package/engine/commands/workforce.cjs +60 -16
- package/engine/core/capability-grants.cjs +7 -2
- package/engine/core/daemon-client.cjs +36 -7
- package/engine/core/db.cjs +10 -2
- package/engine/core/desktop-core-fetch.cjs +477 -77
- package/engine/core/schema-ensure.cjs +23 -11
- package/engine/experience/build.cjs +5 -1
- package/engine/experience/intents.cjs +35 -82
- package/engine/experience/runtime.cjs +7 -1
- package/engine/experience/variant.cjs +58 -4
- package/engine/firms/orchestrate.cjs +9 -6
- package/engine/graph/ask-model.cjs +22 -11
- package/engine/graph/interview.cjs +74 -23
- package/engine/graph/package.cjs +63 -8
- package/engine/hephaestus/local-core.cjs +18 -5
- package/engine/hephaestus/runtime.cjs +48 -43
- package/engine/hub/install.cjs +484 -63
- package/engine/hub/plugins.cjs +391 -29
- package/engine/mcp/consent.cjs +25 -17
- package/engine/mcp/contract.cjs +229 -24
- package/engine/mcp/inventory.cjs +46 -10
- package/engine/mcp/plan.cjs +10 -1
- package/engine/mcp/probe.cjs +24 -9
- package/engine/memory-cli/curate.cjs +74 -16
- package/engine/oberon/common.cjs +37 -12
- package/engine/oberon/manifest.cjs +25 -2
- package/engine/oberon/outputs.cjs +49 -19
- package/engine/oberon/render.cjs +665 -40
- package/engine/project/career-graph.cjs +15 -2
- package/engine/project/controller.cjs +133 -15
- package/engine/project/credentials.cjs +382 -34
- package/engine/project/env-file.cjs +93 -8
- package/engine/project/memory-context.cjs +11 -57
- package/engine/project/ontology.cjs +66 -25
- package/engine/project/paths.cjs +42 -8
- package/engine/project/seed.cjs +88 -51
- package/engine/project/state.cjs +41 -16
- package/engine/project/team.cjs +26 -1
- package/engine/runtime-refusal.cjs +4 -1
- package/engine/runtimes/acp-driver.cjs +56 -9
- package/engine/runtimes/auth-evidence.cjs +21 -2
- package/engine/runtimes/detect.cjs +28 -8
- package/engine/runtimes/kinds.cjs +12 -4
- package/engine/runtimes/overrides.cjs +4 -3
- package/engine/runtimes/resolve.cjs +8 -7
- package/engine/runtimes/roles.cjs +7 -5
- package/engine/sessions/apply-fences.cjs +396 -56
- package/engine/sessions/fences.cjs +111 -27
- package/engine/sessions/memory-turn.cjs +62 -3
- package/engine/sessions/orchestrator.cjs +11 -1
- package/engine/sessions/prompt.cjs +66 -9
- package/engine/sessions/session.cjs +70 -10
- package/engine/sessions/sink.cjs +78 -12
- package/engine/sessions/store.cjs +29 -7
- package/engine/storm/storm.cjs +26 -3
- package/engine/storm/swarm.cjs +31 -3
- package/engine/telegram/connect.cjs +185 -22
- package/engine/ui/commands-catalog.cjs +1 -1
- package/engine/ui/palette.cjs +12 -2
- package/engine/ui/repl.cjs +57 -9
- package/engine/ui/screens.cjs +2 -4
- package/engine/vendor/desktop-core.manifest.json +5 -5
- package/engine/workforce/capture.cjs +9 -27
- package/engine/workforce/deps.cjs +18 -6
- package/engine/workforce/local-core-transport.cjs +68 -5
- package/package.json +1 -1
- package/engine/commands/career-graph.cjs +0 -51
|
@@ -182,6 +182,7 @@ async function runCareerGraphCli(args, opts) {
|
|
|
182
182
|
const sub = normalizedArgs[0] || "status";
|
|
183
183
|
const passivePaths = careerGraphPathsForCli(projectPath);
|
|
184
184
|
if (sub === "status" || sub === "list") {
|
|
185
|
+
if (normalizedArgs.length > 1) throw new Error(`usage: career-graph ${sub}`);
|
|
185
186
|
if (!initializedAgentlasProjectPathCli(projectPath)) {
|
|
186
187
|
return [
|
|
187
188
|
ko ? "커리어 그래프: 초기화되지 않음" : "Career Graph: not initialized",
|
|
@@ -192,7 +193,10 @@ async function runCareerGraphCli(args, opts) {
|
|
|
192
193
|
}
|
|
193
194
|
return formatCareerGraphStatusCli(passivePaths, opts.lang);
|
|
194
195
|
}
|
|
195
|
-
if (sub === "help" || sub === "--help" || sub === "-h")
|
|
196
|
+
if (sub === "help" || sub === "--help" || sub === "-h") {
|
|
197
|
+
if (normalizedArgs.length > 1) throw new Error("usage: career-graph help");
|
|
198
|
+
return careerGraphUsageLinesCli(opts.lang);
|
|
199
|
+
}
|
|
196
200
|
if (["ingest", "query", "verify", "trace"].includes(String(sub))) {
|
|
197
201
|
return [
|
|
198
202
|
ko
|
|
@@ -207,6 +211,15 @@ async function runCareerGraphCli(args, opts) {
|
|
|
207
211
|
const parsed = await parseOntologyNaturalArgsCli(normalizedArgs.join(" "), cwd);
|
|
208
212
|
return runCareerGraphCli(parsed, opts);
|
|
209
213
|
}
|
|
214
|
+
let directFlags = null;
|
|
215
|
+
if (sub === "open") {
|
|
216
|
+
if (normalizedArgs.length !== 1) throw new Error("usage: career-graph open");
|
|
217
|
+
} else if (sub === "add") {
|
|
218
|
+
directFlags = parseFlagsCli(normalizedArgs.slice(1));
|
|
219
|
+
if (directFlags._.length < 1 || directFlags._.length > 3) throw new Error("usage: career-graph add <path> [kind] [scope] [--kind <kind>] [--scope <scope>]");
|
|
220
|
+
if (directFlags.kind !== undefined && directFlags._[1] !== undefined) throw new Error("kind was provided twice; use either the positional value or --kind");
|
|
221
|
+
if (directFlags.scope !== undefined && directFlags._[2] !== undefined) throw new Error("scope was provided twice; use either the positional value or --scope");
|
|
222
|
+
}
|
|
210
223
|
const paths = ensureCareerGraphCli(projectPath, opts.lang);
|
|
211
224
|
if (sub === "open") {
|
|
212
225
|
const opened = opts.noOpen ? true : openLocalPathCli(paths.inboxPath, opts.notify);
|
|
@@ -215,7 +228,7 @@ async function runCareerGraphCli(args, opts) {
|
|
|
215
228
|
: (ko ? "커리어 그래프 수신함을 자동으로 열지 못했습니다. 직접 여세요" : "Could not open Career Graph inbox automatically; open it manually")}: ${paths.inboxPath}`];
|
|
216
229
|
}
|
|
217
230
|
if (sub === "add") {
|
|
218
|
-
const flags =
|
|
231
|
+
const flags = directFlags;
|
|
219
232
|
const source = flags._[0];
|
|
220
233
|
const kind = inferOntologyKindCli(flags.kind || flags._[1], normalizedArgs.join(" "));
|
|
221
234
|
const scope = inferOntologyScopeCli(flags.scope || flags._[2], normalizedArgs.join(" "), kind);
|
|
@@ -4,6 +4,30 @@ const fs = require("node:fs");
|
|
|
4
4
|
const path = require("node:path");
|
|
5
5
|
const { listRoutableAgents } = require("../agents/registry.cjs");
|
|
6
6
|
|
|
7
|
+
const MAX_AGENT_POOL_MEMBERS = 64;
|
|
8
|
+
const MAX_AGENT_POOL_BYTES = 256 * 1024;
|
|
9
|
+
const MAX_AGENT_POOL_MEMBER_BYTES = 8 * 1024;
|
|
10
|
+
const MAX_AGENT_ID_BYTES = 512;
|
|
11
|
+
const MAX_RELEASE_ID_BYTES = 512;
|
|
12
|
+
const MAX_MEMBER_NAME_BYTES = 4 * 1024;
|
|
13
|
+
const MAX_PROJECT_NAME_BYTES = 4 * 1024;
|
|
14
|
+
const MAX_SYSTEM_PROMPT_BYTES = 256 * 1024;
|
|
15
|
+
const MAX_COMBINED_SYSTEM_PROMPT_BYTES = 512 * 1024;
|
|
16
|
+
|
|
17
|
+
function projectError(code, message) {
|
|
18
|
+
return Object.assign(new Error(message), { code, honestStop: true });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function boundedText(value, maxBytes, label, { allowEmpty = false } = {}) {
|
|
22
|
+
if (typeof value !== "string") throw projectError("project_team_unreadable", `This project's ${label} is invalid.`);
|
|
23
|
+
const text = value.trim();
|
|
24
|
+
if (!allowEmpty && !text) throw projectError("project_team_unreadable", `This project's ${label} is empty.`);
|
|
25
|
+
if (Buffer.byteLength(text, "utf8") > maxBytes || /[\u0000\u0001-\u0008\u000b\u000c\u000e-\u001f\u007f]/.test(text)) {
|
|
26
|
+
throw projectError("project_team_unreadable", `This project's ${label} is invalid or too large.`);
|
|
27
|
+
}
|
|
28
|
+
return text;
|
|
29
|
+
}
|
|
30
|
+
|
|
7
31
|
function canonicalPath(value) {
|
|
8
32
|
const resolved = path.resolve(String(value || ""));
|
|
9
33
|
try {
|
|
@@ -27,19 +51,80 @@ function projectColumns(db) {
|
|
|
27
51
|
}
|
|
28
52
|
|
|
29
53
|
function parseAgentPool(raw) {
|
|
54
|
+
if (raw !== undefined && raw !== null && typeof raw !== "string") {
|
|
55
|
+
throw projectError("project_team_unreadable", "This project's agent team cannot be read. Open the project in Agentlas Desktop and save its team again.");
|
|
56
|
+
}
|
|
57
|
+
const encoded = raw === undefined || raw === null ? "[]" : raw;
|
|
58
|
+
if (Buffer.byteLength(encoded, "utf8") > MAX_AGENT_POOL_BYTES) {
|
|
59
|
+
throw projectError("project_team_unreadable", "This project's agent team is too large. Open the project in Agentlas Desktop and save its team again.");
|
|
60
|
+
}
|
|
30
61
|
let parsed;
|
|
31
62
|
try {
|
|
32
|
-
parsed = JSON.parse(
|
|
63
|
+
parsed = JSON.parse(encoded || "[]");
|
|
33
64
|
} catch {
|
|
34
|
-
throw
|
|
65
|
+
throw projectError("project_team_unreadable", "This project's agent team cannot be read. Open the project in Agentlas Desktop and save its team again.");
|
|
35
66
|
}
|
|
36
67
|
if (!Array.isArray(parsed)) {
|
|
37
|
-
throw
|
|
68
|
+
throw projectError("project_team_unreadable", "This project's agent team cannot be read. Open the project in Agentlas Desktop and save its team again.");
|
|
38
69
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
70
|
+
if (parsed.length > MAX_AGENT_POOL_MEMBERS) {
|
|
71
|
+
throw projectError("project_team_too_large", "This project's agent team has too many members. Open the project in Agentlas Desktop and save its team again.");
|
|
72
|
+
}
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
return parsed.map((member, index) => {
|
|
75
|
+
if (!member || typeof member !== "object" || Array.isArray(member)) {
|
|
76
|
+
throw projectError("project_team_unreadable", `This project's agent team member ${index + 1} is invalid.`);
|
|
77
|
+
}
|
|
78
|
+
if (Buffer.byteLength(JSON.stringify(member), "utf8") > MAX_AGENT_POOL_MEMBER_BYTES) {
|
|
79
|
+
throw projectError("project_team_unreadable", `This project's agent team member ${index + 1} is too large.`);
|
|
80
|
+
}
|
|
81
|
+
const keys = Object.keys(member).sort();
|
|
82
|
+
const legacyKeys = ["agentId", "nameSnapshot", "releaseId", "source"];
|
|
83
|
+
const canonicalKeys = ["agentId", "controllerAgentId", "entityKind", "firmId", "nameSnapshot", "releaseId", "source", "targetId"];
|
|
84
|
+
const isLegacy = keys.length === legacyKeys.length && keys.every((key, keyIndex) => key === legacyKeys[keyIndex]);
|
|
85
|
+
const isCanonical = keys.length === canonicalKeys.length && keys.every((key, keyIndex) => key === canonicalKeys[keyIndex]);
|
|
86
|
+
if (!isLegacy && !isCanonical) {
|
|
87
|
+
throw projectError("project_team_unreadable", `This project's agent team member ${index + 1} is incomplete.`);
|
|
88
|
+
}
|
|
89
|
+
const nameSnapshot = boundedText(member.nameSnapshot, MAX_MEMBER_NAME_BYTES, `agent team member ${index + 1} name`);
|
|
90
|
+
if (!["local", "cloud", "hub"].includes(member.source)) {
|
|
91
|
+
throw projectError("project_team_unreadable", `This project's agent team member ${index + 1} has an invalid source.`);
|
|
92
|
+
}
|
|
93
|
+
const releaseId = member.releaseId === null
|
|
94
|
+
? null
|
|
95
|
+
: boundedText(member.releaseId, MAX_RELEASE_ID_BYTES, `agent team member ${index + 1} release`);
|
|
96
|
+
if (isLegacy) {
|
|
97
|
+
const agentId = boundedText(member.agentId, MAX_AGENT_ID_BYTES, `agent team member ${index + 1} agentId`);
|
|
98
|
+
const key = `${member.source}:agent:${agentId}:${releaseId || ""}`;
|
|
99
|
+
if (seen.has(key)) throw projectError("project_team_unreadable", `This project's agent team member ${index + 1} is duplicated.`);
|
|
100
|
+
seen.add(key);
|
|
101
|
+
return {
|
|
102
|
+
entityKind: "agent", targetId: agentId, agentId, firmId: null, controllerAgentId: null,
|
|
103
|
+
source: member.source, releaseId, nameSnapshot,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (member.entityKind !== "agent" && member.entityKind !== "team") {
|
|
108
|
+
throw projectError("project_team_unreadable", `This project's agent team member ${index + 1} has an invalid entity kind.`);
|
|
109
|
+
}
|
|
110
|
+
const optionalId = (value, label) => value === null
|
|
111
|
+
? null
|
|
112
|
+
: boundedText(value, MAX_AGENT_ID_BYTES, `agent team member ${index + 1} ${label}`);
|
|
113
|
+
const targetId = boundedText(member.targetId, MAX_AGENT_ID_BYTES, `agent team member ${index + 1} targetId`);
|
|
114
|
+
const agentId = optionalId(member.agentId, "agentId");
|
|
115
|
+
const firmId = optionalId(member.firmId, "firmId");
|
|
116
|
+
const controllerAgentId = optionalId(member.controllerAgentId, "controllerAgentId");
|
|
117
|
+
if (member.entityKind === "agent" && (firmId !== null || controllerAgentId !== null || (member.source === "local" && agentId === null))) {
|
|
118
|
+
throw projectError("project_team_unreadable", `This project's agent team member ${index + 1} has inconsistent agent identity fields.`);
|
|
119
|
+
}
|
|
120
|
+
if (member.entityKind === "team" && (agentId !== null || (member.source === "local" && firmId === null))) {
|
|
121
|
+
throw projectError("project_team_unreadable", `This project's agent team member ${index + 1} has inconsistent team identity fields.`);
|
|
122
|
+
}
|
|
123
|
+
const key = `${member.source}:${member.entityKind}:${targetId}:${releaseId || ""}`;
|
|
124
|
+
if (seen.has(key)) throw projectError("project_team_unreadable", `This project's agent team member ${index + 1} is duplicated.`);
|
|
125
|
+
seen.add(key);
|
|
126
|
+
return { entityKind: member.entityKind, targetId, agentId, firmId, controllerAgentId, source: member.source, releaseId, nameSnapshot };
|
|
127
|
+
});
|
|
43
128
|
}
|
|
44
129
|
|
|
45
130
|
function resolveProjectForCwd(db, cwd) {
|
|
@@ -64,7 +149,23 @@ function resolveProjectForCwd(db, cwd) {
|
|
|
64
149
|
if (best.length !== 1) {
|
|
65
150
|
throw Object.assign(new Error("More than one Agentlas project is connected to this folder. Keep one source connection, then retry."), { code: "project_ambiguous", honestStop: true });
|
|
66
151
|
}
|
|
67
|
-
|
|
152
|
+
const row = best[0].row;
|
|
153
|
+
boundedText(row.name, MAX_PROJECT_NAME_BYTES, "name");
|
|
154
|
+
if (row.system_prompt !== null && row.system_prompt !== undefined) {
|
|
155
|
+
boundedText(row.system_prompt, MAX_SYSTEM_PROMPT_BYTES, "system prompt", { allowEmpty: true });
|
|
156
|
+
}
|
|
157
|
+
return { ...row, rootPath: best[0].root, agentPool: parseAgentPool(row.agent_pool_json) };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function exactInstalledRelease(db, agentId) {
|
|
161
|
+
try {
|
|
162
|
+
const row = db.prepare(
|
|
163
|
+
"SELECT agent_release_id FROM installed_agent_hub_bindings WHERE installed_agent_id=?",
|
|
164
|
+
).get(agentId);
|
|
165
|
+
return row && typeof row.agent_release_id === "string" ? row.agent_release_id : null;
|
|
166
|
+
} catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
68
169
|
}
|
|
69
170
|
|
|
70
171
|
function resolveProjectController(db, cwd) {
|
|
@@ -73,10 +174,19 @@ function resolveProjectController(db, cwd) {
|
|
|
73
174
|
throw Object.assign(new Error("This project has no agent team. Drag agents into the project in Desktop Work, then retry."), { code: "project_team_empty", honestStop: true });
|
|
74
175
|
}
|
|
75
176
|
const controllerRef = project.agentPool[0];
|
|
76
|
-
|
|
177
|
+
const controllerAgentId = controllerRef.entityKind === "team"
|
|
178
|
+
? controllerRef.controllerAgentId
|
|
179
|
+
: controllerRef.agentId;
|
|
180
|
+
if (!controllerAgentId) {
|
|
77
181
|
throw Object.assign(new Error(`The project controller “${controllerRef.nameSnapshot}” is not installed locally for Terminal execution. Install that exact release locally or reorder the project team.`), { code: "controller_not_installed", honestStop: true });
|
|
78
182
|
}
|
|
79
|
-
|
|
183
|
+
if (controllerRef.entityKind === "team" && controllerRef.source !== "local" && controllerRef.releaseId !== null) {
|
|
184
|
+
throw projectError("controller_release_unavailable", `The project controller team “${controllerRef.nameSnapshot}” needs its exact team release restored before Terminal can execute it.`);
|
|
185
|
+
}
|
|
186
|
+
if (controllerRef.entityKind === "agent" && controllerRef.releaseId !== null && exactInstalledRelease(db, controllerAgentId) !== controllerRef.releaseId) {
|
|
187
|
+
throw projectError("controller_release_unavailable", `The project controller “${controllerRef.nameSnapshot}” is pinned to an unavailable exact release. Restore that release or explicitly choose a new first agent in Desktop Work.`);
|
|
188
|
+
}
|
|
189
|
+
const controller = listRoutableAgents(db).find((agent) => agent.id === controllerAgentId) || null;
|
|
80
190
|
if (!controller) {
|
|
81
191
|
throw Object.assign(new Error(`The project controller “${controllerRef.nameSnapshot}” is unavailable. Restore that agent or explicitly choose a new first agent in Desktop Work.`), { code: "controller_unavailable", honestStop: true });
|
|
82
192
|
}
|
|
@@ -84,22 +194,30 @@ function resolveProjectController(db, cwd) {
|
|
|
84
194
|
}
|
|
85
195
|
|
|
86
196
|
function withProjectControllerContext(controller, project) {
|
|
197
|
+
const projectName = boundedText(project.name, MAX_PROJECT_NAME_BYTES, "name");
|
|
87
198
|
const team = project.agentPool.map((member, index) =>
|
|
88
199
|
`${index + 1}. ${member.nameSnapshot} (${member.source}${member.releaseId ? `, exact release ${member.releaseId}` : ""})`,
|
|
89
200
|
).join("\n");
|
|
90
|
-
const projectInstruction =
|
|
201
|
+
const projectInstruction = project.system_prompt === null || project.system_prompt === undefined
|
|
202
|
+
? ""
|
|
203
|
+
: boundedText(project.system_prompt, MAX_SYSTEM_PROMPT_BYTES, "system prompt", { allowEmpty: true });
|
|
204
|
+
const controllerPrompt = boundedText(controller.systemPrompt || "", MAX_SYSTEM_PROMPT_BYTES, "controller system prompt", { allowEmpty: true });
|
|
91
205
|
const ownership = [
|
|
92
|
-
`You are the controller for the Agentlas Work project “${
|
|
206
|
+
`You are the controller for the Agentlas Work project “${projectName}”.`,
|
|
93
207
|
"You own this task. The remaining ordered project members are eligible sub-agents for task-scoped WorkOrders only.",
|
|
94
208
|
"Do not transfer task ownership, silently substitute an unavailable member, or claim a sub-agent ran without an assignment and execution receipt.",
|
|
95
209
|
"Project team:",
|
|
96
210
|
team,
|
|
97
211
|
].join("\n");
|
|
212
|
+
const systemPrompt = [controllerPrompt, projectInstruction && `Project system prompt:\n${projectInstruction}`, ownership]
|
|
213
|
+
.filter(Boolean)
|
|
214
|
+
.join("\n\n");
|
|
215
|
+
if (Buffer.byteLength(systemPrompt, "utf8") > MAX_COMBINED_SYSTEM_PROMPT_BYTES) {
|
|
216
|
+
throw projectError("project_context_too_large", "This project's controller context is too large to execute safely.");
|
|
217
|
+
}
|
|
98
218
|
return {
|
|
99
219
|
...controller,
|
|
100
|
-
systemPrompt
|
|
101
|
-
.filter(Boolean)
|
|
102
|
-
.join("\n\n"),
|
|
220
|
+
systemPrompt,
|
|
103
221
|
};
|
|
104
222
|
}
|
|
105
223
|
|