@agentdocumentformat/cli 0.8.0 → 0.8.1
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/dist/adf.mjs +6 -6
- package/dist/chunks/{App-A5GUFCFJ.mjs → App-4AZZJNN2.mjs} +511 -406
- package/dist/chunks/{adf-schema-YJSGLMA4.mjs → adf-schema-AIPBQTR2.mjs} +9 -3
- package/dist/chunks/{chunk-AZYOXXVL.mjs → chunk-2Z7X3UUR.mjs} +11 -198
- package/dist/chunks/{chunk-4OGZFUKA.mjs → chunk-7JZXMDDF.mjs} +33 -1
- package/dist/chunks/{chunk-V2T6NZX2.mjs → chunk-AEAJDCVK.mjs} +1 -1
- package/dist/chunks/{chunk-NZO5O4VN.mjs → chunk-BR3AD5QZ.mjs} +7 -1
- package/dist/chunks/{chunk-WVTPPOKK.mjs → chunk-BS3USVEA.mjs} +14 -3
- package/dist/chunks/{chunk-JVPZIMXW.mjs → chunk-D7A77SNL.mjs} +1 -1
- package/dist/chunks/{chunk-LCMANRYY.mjs → chunk-E7LC6SHP.mjs} +1 -1
- package/dist/chunks/{chunk-LGL6ML37.mjs → chunk-F3WSCAJD.mjs} +1 -1
- package/dist/chunks/{chunk-6XQZGYMK.mjs → chunk-IMVMSU3A.mjs} +6 -2
- package/dist/chunks/{chunk-C4GA5SI4.mjs → chunk-KCIRFUZH.mjs} +2 -2
- package/dist/chunks/{chunk-YRMKSHW3.mjs → chunk-LVF2DRBR.mjs} +25 -12
- package/dist/chunks/{chunk-PRPTKMQW.mjs → chunk-RHBGCOS3.mjs} +2 -2
- package/dist/chunks/{chunk-WX6QCUWI.mjs → chunk-RJDOVMM4.mjs} +95 -12
- package/dist/chunks/{chunk-G6NBFYG5.mjs → chunk-SOSPQPEN.mjs} +189 -0
- package/dist/chunks/chunk-VENQBMOA.mjs +62 -0
- package/dist/chunks/{chunk-XT2BJUFC.mjs → chunk-YRBFIDLB.mjs} +33 -6
- package/dist/chunks/{claude-subscription-33BMZB6I.mjs → claude-subscription-EB4LAAVV.mjs} +3 -3
- package/dist/chunks/{cli-I47IFDHJ.mjs → cli-PCVFB6B4.mjs} +5 -5
- package/dist/chunks/{commands-E4EQUHE5.mjs → commands-KOMPXJZS.mjs} +3 -3
- package/dist/chunks/{daemon-FQ5BV3AP.mjs → daemon-BVDB565V.mjs} +729 -111
- package/dist/chunks/{daemon-control-L3CLG63P.mjs → daemon-control-MKN7G5M3.mjs} +4 -4
- package/dist/chunks/{layout-EPJQNFAI.mjs → layout-ECWGJF6M.mjs} +2 -2
- package/dist/chunks/{open-TLGS2Z3Q.mjs → open-3OR6WT4T.mjs} +4 -4
- package/dist/chunks/{pipeline-executor-FD4FBWQA.mjs → pipeline-executor-DRYEEFDR.mjs} +4 -4
- package/dist/chunks/{remote-access-cli-XXAPQWH6.mjs → remote-access-cli-GLEEP7DI.mjs} +2 -2
- package/dist/chunks/sdk-OJOAF4DP.mjs +30014 -0
- package/dist/chunks/{store-ZRN2WCFB.mjs → store-55CQSAOX.mjs} +3 -2
- package/dist/chunks/{tui-SPSPDADM.mjs → tui-RAUVFOYY.mjs} +11 -11
- package/package.json +1 -1
- package/dist/chunks/sdk-5FD2ZP7N.mjs +0 -28422
- package/dist/chunks/{chunk-APRU6PHC.mjs → chunk-JZ7AQNPM.mjs} +3 -3
|
@@ -32,11 +32,6 @@ import {
|
|
|
32
32
|
resolveCompactThreshold,
|
|
33
33
|
resolveLoopThreshold
|
|
34
34
|
} from "./chunk-HBOFZRUS.mjs";
|
|
35
|
-
import {
|
|
36
|
-
formatTurnErrorRow,
|
|
37
|
-
parseLoopToDisplay,
|
|
38
|
-
providerContextCategory
|
|
39
|
-
} from "./chunk-4OGZFUKA.mjs";
|
|
40
35
|
import {
|
|
41
36
|
BUNDLED_REGISTRY_UPDATED_AT,
|
|
42
37
|
MCP_REGISTRY,
|
|
@@ -46,10 +41,11 @@ import {
|
|
|
46
41
|
deriveRegistrationTestPlan,
|
|
47
42
|
isRegistrationAgentVisible,
|
|
48
43
|
isSensitiveMcpHeader,
|
|
44
|
+
isSubscriptionType,
|
|
49
45
|
mcpCredentialRef,
|
|
50
46
|
parseMcpRegistryDocument,
|
|
51
47
|
pinServerConfigToRegistration
|
|
52
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-SOSPQPEN.mjs";
|
|
53
49
|
import {
|
|
54
50
|
TailscaleClient,
|
|
55
51
|
defaultExec,
|
|
@@ -61,16 +57,22 @@ import {
|
|
|
61
57
|
import {
|
|
62
58
|
wrapper_default
|
|
63
59
|
} from "./chunk-F5ELW46V.mjs";
|
|
60
|
+
import {
|
|
61
|
+
formatOwnerCommandRow,
|
|
62
|
+
formatTurnErrorRow,
|
|
63
|
+
parseLoopToDisplay,
|
|
64
|
+
providerContextCategory
|
|
65
|
+
} from "./chunk-7JZXMDDF.mjs";
|
|
64
66
|
import {
|
|
65
67
|
AiSdkProvider,
|
|
66
68
|
createClaudeSubscriptionProvider,
|
|
67
69
|
getTokenCounterService,
|
|
68
70
|
seedMandatoryReasoningModels,
|
|
69
71
|
setMandatoryReasoningPersister
|
|
70
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-KCIRFUZH.mjs";
|
|
71
73
|
import {
|
|
72
74
|
executeNode
|
|
73
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-F3WSCAJD.mjs";
|
|
74
76
|
import {
|
|
75
77
|
ParseError,
|
|
76
78
|
parse
|
|
@@ -138,7 +140,7 @@ import {
|
|
|
138
140
|
withLoop,
|
|
139
141
|
withSource,
|
|
140
142
|
withTurn
|
|
141
|
-
} from "./chunk-
|
|
143
|
+
} from "./chunk-LVF2DRBR.mjs";
|
|
142
144
|
import {
|
|
143
145
|
DEFAULT_BASE_PROMPT,
|
|
144
146
|
DEFAULT_COMPACTION_PROMPT,
|
|
@@ -147,7 +149,7 @@ import {
|
|
|
147
149
|
DOCS_GUIDES_URL,
|
|
148
150
|
MIND_PROMPT_SECTION,
|
|
149
151
|
SOUL_PROMPT_SECTION
|
|
150
|
-
} from "./chunk-
|
|
152
|
+
} from "./chunk-E7LC6SHP.mjs";
|
|
151
153
|
import "./chunk-NZ7JTHEO.mjs";
|
|
152
154
|
import {
|
|
153
155
|
nanoid
|
|
@@ -280,7 +282,7 @@ import {
|
|
|
280
282
|
pidAlive,
|
|
281
283
|
processAgentLeases,
|
|
282
284
|
trustedEndpoint
|
|
283
|
-
} from "./chunk-
|
|
285
|
+
} from "./chunk-D7A77SNL.mjs";
|
|
284
286
|
import {
|
|
285
287
|
NETWORK_PROBLEM_TEXT
|
|
286
288
|
} from "./chunk-3UGZFWIF.mjs";
|
|
@@ -301,7 +303,7 @@ import {
|
|
|
301
303
|
noteLocalProofProblem,
|
|
302
304
|
probeKeychain,
|
|
303
305
|
testSeamsAllowed
|
|
304
|
-
} from "./chunk-
|
|
306
|
+
} from "./chunk-BS3USVEA.mjs";
|
|
305
307
|
import {
|
|
306
308
|
ensureDaemonToken,
|
|
307
309
|
tokensEqual
|
|
@@ -325,9 +327,12 @@ import {
|
|
|
325
327
|
LOOP_NAME_PATTERN,
|
|
326
328
|
LOOP_NAME_RULE,
|
|
327
329
|
LOOP_TOOLS_MAX,
|
|
328
|
-
LoopConfigSchema
|
|
329
|
-
|
|
330
|
-
|
|
330
|
+
LoopConfigSchema
|
|
331
|
+
} from "./chunk-YRBFIDLB.mjs";
|
|
332
|
+
import {
|
|
333
|
+
parseLambdaRef,
|
|
334
|
+
splitArgv
|
|
335
|
+
} from "./chunk-VENQBMOA.mjs";
|
|
331
336
|
import {
|
|
332
337
|
AGENT_DEFAULTS,
|
|
333
338
|
CODE_EXECUTION_DEFAULTS,
|
|
@@ -335,13 +340,15 @@ import {
|
|
|
335
340
|
DEFAULT_NEW_LOOP_TOOLS,
|
|
336
341
|
DEFAULT_TOOLS,
|
|
337
342
|
FILE_PROTECTION_LEVELS,
|
|
343
|
+
MAX_SIDE_LOOPS,
|
|
338
344
|
META_PROTECTION_LEVELS,
|
|
339
345
|
RECOVERY_DEFAULTS,
|
|
340
346
|
RESERVED_AGENT_PATH_SEGMENTS,
|
|
341
347
|
SETTABLE_STATES,
|
|
342
348
|
UPDATABLE_STATES,
|
|
349
|
+
hasLoopGoal,
|
|
343
350
|
resolveStartInState
|
|
344
|
-
} from "./chunk-
|
|
351
|
+
} from "./chunk-BR3AD5QZ.mjs";
|
|
345
352
|
import {
|
|
346
353
|
external_exports
|
|
347
354
|
} from "./chunk-ZJKXHM4Q.mjs";
|
|
@@ -43981,6 +43988,44 @@ import { existsSync as existsSync11, readdirSync as readdirSync5, realpathSync,
|
|
|
43981
43988
|
import { readdir as readdir4, realpath as realpath2 } from "node:fs/promises";
|
|
43982
43989
|
import { basename as basename8, dirname as dirname13, join as join24, resolve as resolve10 } from "node:path";
|
|
43983
43990
|
|
|
43991
|
+
// src/main/adf/loop-teardown.ts
|
|
43992
|
+
function dropTimersForLoop(workspace, name15) {
|
|
43993
|
+
let dropped = 0, kept = 0;
|
|
43994
|
+
for (let timer of workspace.getTimers())
|
|
43995
|
+
if ((timer.loop ?? MAIN_LOOP) === name15) {
|
|
43996
|
+
if (timer.locked) {
|
|
43997
|
+
kept++;
|
|
43998
|
+
continue;
|
|
43999
|
+
}
|
|
44000
|
+
workspace.deleteTimer(timer.id), dropped++;
|
|
44001
|
+
}
|
|
44002
|
+
return { dropped, kept };
|
|
44003
|
+
}
|
|
44004
|
+
async function teardownRemovedLoopsOffline(workspace, previous, next) {
|
|
44005
|
+
let kept = new Set((next.loops ?? []).map((l) => l.name)), removed = (previous.loops ?? []).map((l) => l.name).filter((name15) => name15 !== MAIN_LOOP && !kept.has(name15));
|
|
44006
|
+
for (let name15 of removed) {
|
|
44007
|
+
let log2 = (level, event, message) => {
|
|
44008
|
+
try {
|
|
44009
|
+
workspace.insertLog(level, "loop", event, name15, message);
|
|
44010
|
+
} catch {
|
|
44011
|
+
}
|
|
44012
|
+
};
|
|
44013
|
+
try {
|
|
44014
|
+
let { archivedEntries } = await workspace.forLoop(name15).clearLoop({ forceAudit: !0 });
|
|
44015
|
+
log2("info", "loop_torn_down", archivedEntries > 0 ? `Loop "${name15}" removed via config while the agent was stopped; ${archivedEntries} stream ${archivedEntries === 1 ? "entry" : "entries"} archived to adf_audit under "loop:${name15}"` : `Loop "${name15}" removed via config while the agent was stopped; its stream was empty, nothing to archive`);
|
|
44016
|
+
let timers = dropTimersForLoop(workspace, name15);
|
|
44017
|
+
timers.dropped > 0 && log2("info", "loop_timers_dropped", `Dropped ${timers.dropped} timer(s) belonging to deleted loop "${name15}" \u2014 orphaned timers are never re-pointed at main`), timers.kept > 0 && log2("warn", "loop_timers_locked_kept", `Kept ${timers.kept} locked timer(s) belonging to deleted loop "${name15}" \u2014 a lock is human-only and survives the loop; unlock or delete them in Studio`);
|
|
44018
|
+
} catch (error) {
|
|
44019
|
+
console.error(`[LoopTeardown] Teardown of removed loop "${name15}" failed:`, error), log2(
|
|
44020
|
+
"error",
|
|
44021
|
+
"loop_teardown_failed",
|
|
44022
|
+
`Teardown of removed loop "${name15}" failed; its stream may still be in adf_loop: ${error instanceof Error ? error.message : String(error)}`
|
|
44023
|
+
);
|
|
44024
|
+
}
|
|
44025
|
+
}
|
|
44026
|
+
return removed;
|
|
44027
|
+
}
|
|
44028
|
+
|
|
43984
44029
|
// src/main/adf/apply-default-provider.ts
|
|
43985
44030
|
function toAdfProviderConfig(p) {
|
|
43986
44031
|
let adf = {
|
|
@@ -58226,6 +58271,7 @@ function expectsNumber(path) {
|
|
|
58226
58271
|
return NUMERIC_LEAF_NAMES.has(leaf) || NUMERIC_LEAF_SUFFIX.test(leaf);
|
|
58227
58272
|
}
|
|
58228
58273
|
var DECLARATION_ARRAYS = /* @__PURE__ */ new Set([
|
|
58274
|
+
"commands",
|
|
58229
58275
|
"tools",
|
|
58230
58276
|
"serving.api",
|
|
58231
58277
|
"ws_connections",
|
|
@@ -58303,8 +58349,10 @@ var InputSchema6 = external_exports.object({
|
|
|
58303
58349
|
return this.err(`Invalid input: ${parsed.error.issues.map((i) => i.message).join("; ")}`);
|
|
58304
58350
|
try {
|
|
58305
58351
|
let { path, value, index } = parsed.data, action = parsed.data.action ?? "set", segments = this.parsePath(path);
|
|
58352
|
+
if (!isAuthorized && segments[0] === "commands" && segments[segments.length - 1] === "locked" && value === !0)
|
|
58353
|
+
return this.err("Only the owner can lock a command.");
|
|
58306
58354
|
for (let seg of segments) {
|
|
58307
|
-
if (seg === "locked" || seg === "locked_fields")
|
|
58355
|
+
if (seg === "locked" && !(isAuthorized && segments[0] === "commands") || seg === "locked_fields")
|
|
58308
58356
|
return this.err("Cannot modify locking configuration.");
|
|
58309
58357
|
if (seg === "restricted" || seg === "restricted_methods")
|
|
58310
58358
|
return this.err("Cannot modify restriction configuration.");
|
|
@@ -58331,11 +58379,11 @@ var InputSchema6 = external_exports.object({
|
|
|
58331
58379
|
let lockViolation = this.checkLocks(config, resolved);
|
|
58332
58380
|
if (lockViolation && !isAuthorized && !isOverride)
|
|
58333
58381
|
return this.errProtected(lockViolation, this.lockDescription(path, value, action));
|
|
58334
|
-
let valErr = this.validateField(
|
|
58382
|
+
let valErr = this.validateField(resolved.join("."), value, action, workspace);
|
|
58335
58383
|
if (valErr) return this.err(valErr);
|
|
58336
|
-
let declErr = this.checkDeclarationIntegrity(config, resolved, value, action);
|
|
58384
|
+
let declErr = this.checkDeclarationIntegrity(config, resolved, value, action, isAuthorized);
|
|
58337
58385
|
if (declErr) return this.err(declErr);
|
|
58338
|
-
let snapshot = cloneConfig(config), issuesBefore = schemaIssueKeys(snapshot), applyErr = this.applyChange(config, resolved, value, action, index, isOverride);
|
|
58386
|
+
let snapshot = cloneConfig(config), issuesBefore = schemaIssueKeys(snapshot), applyErr = this.applyChange(config, resolved, value, action, index, isOverride || isAuthorized);
|
|
58339
58387
|
if (applyErr) return typeof applyErr == "string" ? this.err(applyErr) : this.errProtected(applyErr, this.lockDescription(path, value, action));
|
|
58340
58388
|
let issuesAfter = schemaIssueKeys(config), introduced = [...issuesAfter.keys()].filter((key) => !issuesBefore.has(key));
|
|
58341
58389
|
if (introduced.length > 0 || issuesAfter.size > issuesBefore.size) {
|
|
@@ -58421,7 +58469,16 @@ var InputSchema6 = external_exports.object({
|
|
|
58421
58469
|
// ---------------------------------------------------------------------------
|
|
58422
58470
|
// Field validation
|
|
58423
58471
|
// ---------------------------------------------------------------------------
|
|
58424
|
-
validateField(path, value, action) {
|
|
58472
|
+
validateField(path, value, action, workspace) {
|
|
58473
|
+
if (action !== "remove" && /^commands(?:\.\d+(?:\.lambda)?)?$/.test(path)) {
|
|
58474
|
+
let entries = path.endsWith(".lambda") ? [{ lambda: value }] : Array.isArray(value) ? value : [value];
|
|
58475
|
+
for (let entry of entries) {
|
|
58476
|
+
if (!entry || typeof entry != "object" || typeof entry.lambda != "string") continue;
|
|
58477
|
+
let ref = parseLambdaRef(entry.lambda);
|
|
58478
|
+
if ("error" in ref) return ref.error;
|
|
58479
|
+
if (workspace.readFile(ref.file) === null) return `Lambda file "${ref.file}" not found. Write it first, then register the command.`;
|
|
58480
|
+
}
|
|
58481
|
+
}
|
|
58425
58482
|
if (path === "name") {
|
|
58426
58483
|
if (typeof value != "string" || value.trim().length === 0)
|
|
58427
58484
|
return "name must be a non-empty string";
|
|
@@ -58496,14 +58553,16 @@ var InputSchema6 = external_exports.object({
|
|
|
58496
58553
|
* the tool's effective declaration (current config, else DEFAULT_TOOLS)
|
|
58497
58554
|
* has that flag true.
|
|
58498
58555
|
*/
|
|
58499
|
-
checkDeclarationIntegrity(config, segments, value, action) {
|
|
58556
|
+
checkDeclarationIntegrity(config, segments, value, action, isAuthorized) {
|
|
58500
58557
|
if (action === "remove") return null;
|
|
58501
58558
|
let normalized = segments.filter((seg) => typeof seg != "number").join(".");
|
|
58502
58559
|
if (!DECLARATION_ARRAYS.has(normalized)) return null;
|
|
58503
58560
|
let isElementSet = action === "set" && typeof segments[segments.length - 1] == "number", incoming = action === "append" ? [value] : isElementSet ? [value] : Array.isArray(value) ? value : [];
|
|
58504
58561
|
if (incoming.length === 0) return null;
|
|
58505
|
-
let existingArray = this.readArrayAt(config, isElementSet ? segments.slice(0, -1) : segments), replacedIndex = isElementSet ? segments[segments.length - 1] : -1, siblings = (existingArray ?? []).filter((_, i) => i !== replacedIndex), seen = /* @__PURE__ */ new Set();
|
|
58562
|
+
let existingArray = this.readArrayAt(config, isElementSet ? segments.slice(0, -1) : segments), replacedIndex = isElementSet ? segments[segments.length - 1] : -1, siblings = normalized === "commands" && action === "set" && !isElementSet ? [] : (existingArray ?? []).filter((_, i) => i !== replacedIndex), seen = /* @__PURE__ */ new Set();
|
|
58506
58563
|
for (let entry of incoming) {
|
|
58564
|
+
if (normalized === "commands" && !isAuthorized && entry && typeof entry == "object" && entry.locked === !0)
|
|
58565
|
+
return "Only the owner can lock a command.";
|
|
58507
58566
|
let key = declarationKey(entry);
|
|
58508
58567
|
if (!key) continue;
|
|
58509
58568
|
if (seen.has(key) || siblings.some((el) => declarationKey(el) === key))
|
|
@@ -59287,6 +59346,7 @@ function mergeTemplateWithOverrides(templateConfig, overrides) {
|
|
|
59287
59346
|
"mcp",
|
|
59288
59347
|
"adapters",
|
|
59289
59348
|
"serving",
|
|
59349
|
+
"commands",
|
|
59290
59350
|
"providers",
|
|
59291
59351
|
"ws_connections",
|
|
59292
59352
|
"locked_fields",
|
|
@@ -59304,7 +59364,10 @@ function mergeTemplateWithOverrides(templateConfig, overrides) {
|
|
|
59304
59364
|
if (!mergedTriggers.ok) return mergedTriggers;
|
|
59305
59365
|
let mergedServing = mergeServing(templateConfig.serving, overrides.serving);
|
|
59306
59366
|
if (!mergedServing.ok) return mergedServing;
|
|
59307
|
-
let
|
|
59367
|
+
let lockedCommands = (templateConfig.commands ?? []).filter((command) => command.locked);
|
|
59368
|
+
if (overrides.commands?.some((command) => lockedCommands.some((locked) => locked.name === command.name)))
|
|
59369
|
+
return { ok: !1, error: "Cannot override a locked template command" };
|
|
59370
|
+
let commands = overrides.commands === void 0 ? templateConfig.commands : [...lockedCommands, ...overrides.commands], options = {
|
|
59308
59371
|
name: overrides.name ?? templateConfig.name,
|
|
59309
59372
|
description: overrides.description ?? templateConfig.description,
|
|
59310
59373
|
instructions: overrides.instructions ?? templateConfig.instructions,
|
|
@@ -59333,6 +59396,7 @@ function mergeTemplateWithOverrides(templateConfig, overrides) {
|
|
|
59333
59396
|
...overrides.logging ?? templateConfig.logging ? { logging: overrides.logging ?? templateConfig.logging } : {},
|
|
59334
59397
|
...overrides.mcp ?? templateConfig.mcp ? { mcp: overrides.mcp ?? templateConfig.mcp } : {},
|
|
59335
59398
|
...overrides.adapters ?? templateConfig.adapters ? { adapters: overrides.adapters ?? templateConfig.adapters } : {},
|
|
59399
|
+
...commands ? { commands } : {},
|
|
59336
59400
|
...mergedServing.value ? { serving: mergedServing.value } : {},
|
|
59337
59401
|
...overrides.providers ?? templateConfig.providers ? { providers: overrides.providers ?? templateConfig.providers } : {},
|
|
59338
59402
|
...overrides.ws_connections ?? templateConfig.ws_connections ? { ws_connections: overrides.ws_connections ?? templateConfig.ws_connections } : {},
|
|
@@ -63701,6 +63765,10 @@ import { join as join8, dirname as dirname5 } from "path";
|
|
|
63701
63765
|
|
|
63702
63766
|
// src/main/utils/atomic-json.ts
|
|
63703
63767
|
import {
|
|
63768
|
+
closeSync,
|
|
63769
|
+
fsyncSync,
|
|
63770
|
+
openSync,
|
|
63771
|
+
writeSync,
|
|
63704
63772
|
readFileSync as readFileSync2,
|
|
63705
63773
|
writeFileSync as writeFileSync2,
|
|
63706
63774
|
renameSync as renameSync2,
|
|
@@ -64510,9 +64578,13 @@ init_execution_context();
|
|
|
64510
64578
|
init_emit_umbilical();
|
|
64511
64579
|
|
|
64512
64580
|
// src/main/runtime/runtime-gate.ts
|
|
64513
|
-
var RuntimeGateImpl = class {
|
|
64581
|
+
var KILL_IN_PROGRESS_ERROR = "Kill is still stopping agents. Start it again once it finishes.", RuntimeGateImpl = class {
|
|
64514
64582
|
_stopped = !1;
|
|
64515
64583
|
_teardown = !1;
|
|
64584
|
+
_kills = 0;
|
|
64585
|
+
_killEpoch = 0;
|
|
64586
|
+
_killSettled = Promise.resolve();
|
|
64587
|
+
_settleKill = null;
|
|
64516
64588
|
get stopped() {
|
|
64517
64589
|
return this._stopped;
|
|
64518
64590
|
}
|
|
@@ -64520,9 +64592,43 @@ var RuntimeGateImpl = class {
|
|
|
64520
64592
|
get tearingDown() {
|
|
64521
64593
|
return this._teardown;
|
|
64522
64594
|
}
|
|
64595
|
+
/** True while a Kill is stopping agents (between beginKill and its release). */
|
|
64596
|
+
get killing() {
|
|
64597
|
+
return this._kills > 0;
|
|
64598
|
+
}
|
|
64599
|
+
/**
|
|
64600
|
+
* Counts the Kills begun. A start that awaits before it starts anything (a
|
|
64601
|
+
* provider check, a folder scan) takes it first and refuses when
|
|
64602
|
+
* `killedSince` says a Kill began in between: a start the user asked for
|
|
64603
|
+
* before the Kill is not carried out after it.
|
|
64604
|
+
*/
|
|
64605
|
+
get killEpoch() {
|
|
64606
|
+
return this._killEpoch;
|
|
64607
|
+
}
|
|
64608
|
+
killedSince(epoch) {
|
|
64609
|
+
return this._killEpoch !== epoch || this._kills > 0;
|
|
64610
|
+
}
|
|
64523
64611
|
stop() {
|
|
64524
64612
|
this._stopped || (this._stopped = !0, console.log("[RuntimeGate] stopped"));
|
|
64525
64613
|
}
|
|
64614
|
+
/**
|
|
64615
|
+
* A Kill begins: the gate closes and stays closed until the returned
|
|
64616
|
+
* release runs (call it in a finally). Overlapping Kills nest. After the
|
|
64617
|
+
* release the gate is still stopped: only a deliberate start reopens it.
|
|
64618
|
+
*/
|
|
64619
|
+
beginKill() {
|
|
64620
|
+
this.stop(), this._killEpoch++, this._kills++ === 0 && (this._killSettled = new Promise((resolve20) => {
|
|
64621
|
+
this._settleKill = resolve20;
|
|
64622
|
+
}));
|
|
64623
|
+
let released = !1;
|
|
64624
|
+
return () => {
|
|
64625
|
+
released || (released = !0, --this._kills === 0 && (this._settleKill?.(), this._settleKill = null));
|
|
64626
|
+
};
|
|
64627
|
+
}
|
|
64628
|
+
/** Resolves once no Kill is running (at once when none is). */
|
|
64629
|
+
whenKillSettled() {
|
|
64630
|
+
return this._killSettled;
|
|
64631
|
+
}
|
|
64526
64632
|
/**
|
|
64527
64633
|
* Terminal stop for process shutdown. After this, `resume()` no-ops and
|
|
64528
64634
|
* `stopped` remains true until process exit.
|
|
@@ -64535,11 +64641,15 @@ var RuntimeGateImpl = class {
|
|
|
64535
64641
|
console.warn("[RuntimeGate] resume() ignored \u2014 runtime teardown in progress");
|
|
64536
64642
|
return;
|
|
64537
64643
|
}
|
|
64644
|
+
if (this._kills > 0) {
|
|
64645
|
+
console.warn("[RuntimeGate] resume() refused \u2014 Kill is still stopping agents");
|
|
64646
|
+
return;
|
|
64647
|
+
}
|
|
64538
64648
|
this._stopped && (this._stopped = !1, console.log("[RuntimeGate] resumed"));
|
|
64539
64649
|
}
|
|
64540
|
-
/** Test-only escape hatch: clears stopped/teardown state. Never call in production code. */
|
|
64650
|
+
/** Test-only escape hatch: clears stopped/teardown/kill state. Never call in production code. */
|
|
64541
64651
|
_resetForTests() {
|
|
64542
|
-
this._stopped = !1, this._teardown = !1;
|
|
64652
|
+
this._stopped = !1, this._teardown = !1, this._kills = 0, this._killEpoch = 0, this._settleKill?.(), this._settleKill = null, this._killSettled = Promise.resolve();
|
|
64543
64653
|
}
|
|
64544
64654
|
}, RuntimeGate = new RuntimeGateImpl();
|
|
64545
64655
|
|
|
@@ -65130,6 +65240,8 @@ var AgentExecutor = class _AgentExecutor extends EventEmitter3 {
|
|
|
65130
65240
|
session;
|
|
65131
65241
|
config;
|
|
65132
65242
|
basePrompt;
|
|
65243
|
+
/** Settings' app system prompt, read each turn: an edit applies at the next turn (setBasePromptSource). */
|
|
65244
|
+
basePromptSource = null;
|
|
65133
65245
|
toolPrompts;
|
|
65134
65246
|
compactionPrompt;
|
|
65135
65247
|
abortController = null;
|
|
@@ -65175,6 +65287,8 @@ var AgentExecutor = class _AgentExecutor extends EventEmitter3 {
|
|
|
65175
65287
|
// Turns running OR already committed to run (see isTurnActive). Not a state
|
|
65176
65288
|
// machine — a counter, because error-recovery retries nest executeTurn calls
|
|
65177
65289
|
// and a re-entrant successor claims its slot before its predecessor releases.
|
|
65290
|
+
pendingOwnerCommandRecords = [];
|
|
65291
|
+
ownerCommandRecordsClosed = !1;
|
|
65178
65292
|
activeTurnCount = 0;
|
|
65179
65293
|
// Agent-scope subset of activeTurnCount. The concurrent-turn guard reads THIS
|
|
65180
65294
|
// one: a system-scope dispatch (lambda handler) never touches the session, so
|
|
@@ -66058,7 +66172,7 @@ var AgentExecutor = class _AgentExecutor extends EventEmitter3 {
|
|
|
66058
66172
|
let loop = this.umbilicalLoop(), run2 = () => this.executeTurnImpl(dispatch, opts, turnId), correlated = () => withTurn(dispatch.turnId ?? turnId, () => loop ? withLoop(loop, run2) : run2());
|
|
66059
66173
|
return await withSource(`agent:${turnId}`, this.config.id, correlated);
|
|
66060
66174
|
} finally {
|
|
66061
|
-
if (this.activeTurnCount--, dispatch.scope !== "system" ? this.activeAgentTurnCount-- : this.activeAgentTurnCount === 0 && this.betweenTurns() && this.drainPendingTriggers(), this.activeAgentTurnCount === 0 && this.writeDiscardNotice(), this.activeTurnCount === 0 && this.onTurnSettled)
|
|
66175
|
+
if (this.activeTurnCount--, dispatch.scope !== "system" ? this.activeAgentTurnCount-- : this.activeAgentTurnCount === 0 && this.betweenTurns() && this.drainPendingTriggers(), this.activeTurnCount === 0 && this.flushOwnerCommandRecords(), this.activeAgentTurnCount === 0 && this.writeDiscardNotice(), this.activeTurnCount === 0 && this.onTurnSettled)
|
|
66062
66176
|
try {
|
|
66063
66177
|
this.onTurnSettled();
|
|
66064
66178
|
} catch (error) {
|
|
@@ -66145,7 +66259,7 @@ var AgentExecutor = class _AgentExecutor extends EventEmitter3 {
|
|
|
66145
66259
|
} finally {
|
|
66146
66260
|
this.compactionFailedThisTurn = failedBefore, this.manualCompactionActive = !1, this._interruptRestart = !1;
|
|
66147
66261
|
let replayed = this.getState() !== "stopped" && this.replayQueuedChats();
|
|
66148
|
-
if (this.activeTurnCount--, this.activeAgentTurnCount--, !replayed && this.activeAgentTurnCount === 0 && this.betweenTurns() && this.drainPendingTriggers(), this.activeAgentTurnCount === 0 && this.writeDiscardNotice(), this.activeTurnCount === 0 && this.onTurnSettled)
|
|
66262
|
+
if (this.activeTurnCount--, this.activeAgentTurnCount--, !replayed && this.activeAgentTurnCount === 0 && this.betweenTurns() && this.drainPendingTriggers(), this.activeTurnCount === 0 && this.flushOwnerCommandRecords(), this.activeAgentTurnCount === 0 && this.writeDiscardNotice(), this.activeTurnCount === 0 && this.onTurnSettled)
|
|
66149
66263
|
try {
|
|
66150
66264
|
this.onTurnSettled();
|
|
66151
66265
|
} catch (error) {
|
|
@@ -66357,7 +66471,7 @@ var AgentExecutor = class _AgentExecutor extends EventEmitter3 {
|
|
|
66357
66471
|
timestamp: Date.now()
|
|
66358
66472
|
}), chatTokens = await this.forceCompact(`auto: ${chatTokens} >= ${compactThreshold}`)) : (this.memoryFlushNudgeIssued = !0, this.addRuntimeNotice("Context is about to be compacted. Before that happens: write any durable learnings from this loop to your mind pages (update mind.md index + mind/log.md), citing source messages by their [S<seq>] markers. Track unfinished work on an open-thread page. Then continue \u2014 compaction follows automatically.")));
|
|
66359
66473
|
let systemPrompt = this.buildSystemPrompt(), dynamicInstructions = this.buildDynamicInstructions(chatTokens, compactThreshold);
|
|
66360
|
-
if (this.recordRequestContext(systemPrompt, dynamicInstructions), this.session.drainContextInjections(), opts?.nested || this.deliverQueuedChats("next_step"), !this.providerValidated && this.provider) {
|
|
66474
|
+
if (this.recordRequestContext(systemPrompt, dynamicInstructions), this.session.drainContextInjections(), this.flushOwnerCommandRecords(), opts?.nested || this.deliverQueuedChats("next_step"), !this.providerValidated && this.provider) {
|
|
66361
66475
|
let validation = await this.provider.validateConfig();
|
|
66362
66476
|
if (!validation.valid) {
|
|
66363
66477
|
let preflightError = validation.error || "unknown";
|
|
@@ -67855,6 +67969,29 @@ Use start_line/end_line to read sections (e.g. start_line=1, end_line=100).
|
|
|
67855
67969
|
* Truncate oversized tool results to protect the context window.
|
|
67856
67970
|
* Uses a fast char-based pre-filter; only tokenizes when borderline.
|
|
67857
67971
|
*/
|
|
67972
|
+
/** Apply the configured tool-result bounds before retaining a command result. */
|
|
67973
|
+
boundToolResult(content, label) {
|
|
67974
|
+
return this.enforceToolResultLimit({ content, isError: !1 }, label).content;
|
|
67975
|
+
}
|
|
67976
|
+
recordOwnerCommand(text) {
|
|
67977
|
+
if (this.ownerCommandRecordsClosed) {
|
|
67978
|
+
try {
|
|
67979
|
+
this.session.getWorkspace().insertLog("warn", "command", "record_discarded", null, "Command completed after executor disposal.");
|
|
67980
|
+
} catch {
|
|
67981
|
+
}
|
|
67982
|
+
return { deferred: !1 };
|
|
67983
|
+
}
|
|
67984
|
+
if (this.isTurnActive())
|
|
67985
|
+
return this.pendingOwnerCommandRecords.push(text), { deferred: !0 };
|
|
67986
|
+
let content = [{ type: "text", text }], seq = this.session.getWorkspace().appendToLoop("user", content);
|
|
67987
|
+
return this.session.getMessages().length > 0 && this.session.addMessage({ role: "user", content }, void 0, { skipLoop: !0, seq }), this.emitEvent({ type: "context_injected", payload: { category: "owner_command", content: text, seq }, timestamp: Date.now() }), { deferred: !1, seq };
|
|
67988
|
+
}
|
|
67989
|
+
flushOwnerCommandRecords() {
|
|
67990
|
+
for (; this.pendingOwnerCommandRecords.length > 0; ) {
|
|
67991
|
+
let text = this.pendingOwnerCommandRecords[0], message = { role: "user", content: [{ type: "text", text }] }, seq;
|
|
67992
|
+
this.session.getMessages().length === 0 ? seq = this.session.getWorkspace().appendToLoop("user", message.content) : (this.session.addMessage(message), this.session.flushToLoop(), seq = message.seq), this.pendingOwnerCommandRecords.shift(), this.emitEvent({ type: "context_injected", payload: { category: "owner_command", content: text, seq }, timestamp: Date.now() });
|
|
67993
|
+
}
|
|
67994
|
+
}
|
|
67858
67995
|
enforceToolResultLimit(result, toolName) {
|
|
67859
67996
|
let maxTokens = this.config.limits?.max_tool_result_tokens ?? 16e3, content = result.content;
|
|
67860
67997
|
if (content.length <= maxTokens * 3) return result;
|
|
@@ -67891,7 +68028,7 @@ ${tail}` : ""}`;
|
|
|
67891
68028
|
[TRUNCATED \u2014 content exceeded ${maxTokens.toLocaleString()} token limit]`;
|
|
67892
68029
|
}
|
|
67893
68030
|
setState(state) {
|
|
67894
|
-
state === "idle" && this.besideTurnHilTasks.size > 0 && (state = "awaiting_approval"), state !== "error" && (this._errorReason = null, this._recoverySuppressedLogged = !1), this.state = state, this.emitEvent({
|
|
68031
|
+
state === "idle" && this.besideTurnHilTasks.size > 0 && (state = "awaiting_approval"), state !== "error" && (this._errorReason = null, this._recoverySuppressedLogged = !1), state !== "stopped" && (this.ownerCommandRecordsClosed = !1), this.state = state, this.emitEvent({
|
|
67895
68032
|
type: "state_changed",
|
|
67896
68033
|
payload: { state },
|
|
67897
68034
|
timestamp: Date.now()
|
|
@@ -68417,7 +68554,21 @@ ${tail}` : ""}`;
|
|
|
68417
68554
|
prompt
|
|
68418
68555
|
}, prompt;
|
|
68419
68556
|
}
|
|
68557
|
+
/**
|
|
68558
|
+
* Read the app system prompt from the host's settings at every turn, so an
|
|
68559
|
+
* edit applies at the next turn, not the next start. A non-string value
|
|
68560
|
+
* keeps the prompt the executor has.
|
|
68561
|
+
*/
|
|
68562
|
+
setBasePromptSource(read) {
|
|
68563
|
+
this.basePromptSource = read;
|
|
68564
|
+
}
|
|
68565
|
+
/** The app system prompt this executor assembles with now. */
|
|
68566
|
+
getBasePrompt() {
|
|
68567
|
+
return this.basePrompt;
|
|
68568
|
+
}
|
|
68420
68569
|
assembleSystemPrompt() {
|
|
68570
|
+
let live = this.basePromptSource?.();
|
|
68571
|
+
typeof live == "string" && (this.basePrompt = live);
|
|
68421
68572
|
let enabledToolNames = this.config.tools.filter((t) => t.enabled).map((t) => t.name).sort(), enabledTools = new Set(enabledToolNames), bare = this.config.bare_prompt === !0, includeBase = !bare && this.config.include_base_prompt !== !1, fullSections = assemblePrompt({
|
|
68422
68573
|
config: this.config,
|
|
68423
68574
|
basePrompt: this.basePrompt,
|
|
@@ -68432,6 +68583,8 @@ ${this.config.instructions}`
|
|
|
68432
68583
|
JSON.stringify({
|
|
68433
68584
|
name: this.config.name,
|
|
68434
68585
|
instructions: this.config.instructions,
|
|
68586
|
+
// The app system prompt can change mid-session (setBasePromptSource).
|
|
68587
|
+
base_prompt: this.hashString(this.basePrompt),
|
|
68435
68588
|
include_base_prompt: this.config.include_base_prompt,
|
|
68436
68589
|
bare_prompt: this.config.bare_prompt,
|
|
68437
68590
|
tools: enabledToolNames,
|
|
@@ -68661,6 +68814,7 @@ You have native ${modalityList} perception enabled. Two ways to perceive media:
|
|
|
68661
68814
|
* a System notice goes to the live transcript, adf_logs and the loop.
|
|
68662
68815
|
*/
|
|
68663
68816
|
discardQueuedChats(reason) {
|
|
68817
|
+
this.activeAgentTurnCount === 0 && this.flushOwnerCommandRecords(), this.ownerCommandRecordsClosed = !0;
|
|
68664
68818
|
let chats = this.pendingChats.splice(0), unanswered = this.absorbedTurnIds.splice(0);
|
|
68665
68819
|
if (this.runningTurnId && !unanswered.includes(this.runningTurnId) && unanswered.push(this.runningTurnId), chats.length === 0 && unanswered.length === 0) return;
|
|
68666
68820
|
let ids = chats.flatMap((chat) => chat.turnId ? [chat.turnId] : []);
|
|
@@ -70273,12 +70427,12 @@ var LoopConfigInputSchema = external_exports.object({
|
|
|
70273
70427
|
name: external_exports.string().regex(LOOP_NAME_PATTERN, { message: LOOP_NAME_RULE }).optional().describe(
|
|
70274
70428
|
'Loop name: 1-32 lowercase chars; unique here, "main" reserved.'
|
|
70275
70429
|
),
|
|
70276
|
-
goal: external_exports.string().
|
|
70277
|
-
"The loop's charter
|
|
70430
|
+
goal: external_exports.string().max(LOOP_GOAL_MAX_CHARS).optional().describe(
|
|
70431
|
+
"The loop's charter, appended to its instructions. Optional: without one the loop works on whatever it is sent. Required when autostart is true."
|
|
70278
70432
|
),
|
|
70279
70433
|
enabled: external_exports.boolean().optional().describe("Whether the loop runs. Default true on create."),
|
|
70280
70434
|
autostart: external_exports.boolean().optional().describe(
|
|
70281
|
-
"Run a first turn on the goal without waiting to be addressed: now on create, and again whenever the agent starts. Default true on create. false: it only runs when a trigger, timer or loop_send targets it."
|
|
70435
|
+
"Run a first turn on the goal without waiting to be addressed: now on create, and again whenever the agent starts. Default true on create, and needs a goal: creating without a goal requires autostart false. false: it only runs when a trigger, timer or loop_send targets it."
|
|
70282
70436
|
),
|
|
70283
70437
|
autonomous: external_exports.boolean().optional().describe(
|
|
70284
70438
|
"Keep turning after text-only responses until the loop calls sys_set_state. Not inherited from you; default false. Grant sys_set_state alongside."
|
|
@@ -70360,7 +70514,7 @@ var LoopManageTool = class {
|
|
|
70360
70514
|
// Mutations
|
|
70361
70515
|
// ---------------------------------------------------------------------------
|
|
70362
70516
|
async handleCreate(pool, workspace, nameArg, configArg) {
|
|
70363
|
-
if (!configArg) return errorResult('create requires "config" (at least name
|
|
70517
|
+
if (!configArg) return errorResult('create requires "config" (at least a name).');
|
|
70364
70518
|
let name15 = configArg.name ?? nameArg;
|
|
70365
70519
|
if (!name15) return errorResult('create requires a loop name, in "config.name" or "name".');
|
|
70366
70520
|
if (configArg.name && nameArg && configArg.name !== nameArg)
|
|
@@ -70376,7 +70530,7 @@ var LoopManageTool = class {
|
|
|
70376
70530
|
);
|
|
70377
70531
|
let candidate = {
|
|
70378
70532
|
name: name15,
|
|
70379
|
-
goal: configArg.goal,
|
|
70533
|
+
...configArg.goal !== void 0 && { goal: configArg.goal },
|
|
70380
70534
|
enabled: configArg.enabled ?? !0,
|
|
70381
70535
|
// Persisted, like the agent's own `autostart`: the pool re-kicks the loop
|
|
70382
70536
|
// on every agent start. Default on — a loop nobody addresses is idle,
|
|
@@ -70409,7 +70563,7 @@ var LoopManageTool = class {
|
|
|
70409
70563
|
}
|
|
70410
70564
|
return {
|
|
70411
70565
|
content: `Created loop "${name15}"${validated.config.enabled ? " (running)" : " (disabled)"}.
|
|
70412
|
-
Goal: ${validated.config.goal}
|
|
70566
|
+
Goal: ${validated.config.goal?.trim() ? validated.config.goal : "(none)"}
|
|
70413
70567
|
Tools: ${toolLine}.${this.disabledNote(validated.disabled)}
|
|
70414
70568
|
` + startLine,
|
|
70415
70569
|
isError: !1
|
|
@@ -75277,7 +75431,7 @@ var LoopPool = class _LoopPool {
|
|
|
75277
75431
|
isMain: !0
|
|
75278
75432
|
}, side = (host2.loops ?? []).map((loop) => ({
|
|
75279
75433
|
name: loop.name,
|
|
75280
|
-
goal: loop.goal,
|
|
75434
|
+
goal: loop.goal ?? "",
|
|
75281
75435
|
status: this.runtimes.get(loop.name)?.status() ?? "idle",
|
|
75282
75436
|
enabled: loop.enabled !== !1,
|
|
75283
75437
|
isMain: !1
|
|
@@ -75475,13 +75629,19 @@ var LoopPool = class _LoopPool {
|
|
|
75475
75629
|
if (this.disposed) return [];
|
|
75476
75630
|
let woken = [];
|
|
75477
75631
|
for (let loop of this.declaredLoops())
|
|
75478
|
-
if (!(!loop.autostart || loop.enabled === !1) && this.runtimes.has(loop.name))
|
|
75632
|
+
if (!(!loop.autostart || loop.enabled === !1) && this.runtimes.has(loop.name)) {
|
|
75633
|
+
if (!hasLoopGoal(loop)) {
|
|
75634
|
+
let message = `Autostart of loop "${loop.name}" refused: it has no goal. Add a goal or turn autostart off.`;
|
|
75635
|
+
console.warn(`[LoopPool] ${message}`), this.logLoop("warn", "loop_autostart_refused", loop.name, message);
|
|
75636
|
+
continue;
|
|
75637
|
+
}
|
|
75479
75638
|
try {
|
|
75480
75639
|
let result = await this.sendToLoop(MAIN_LOOP, loop.name, LOOP_AUTOSTART_MESSAGE, !0);
|
|
75481
75640
|
result.woke ? woken.push(loop.name) : console.warn(`[LoopPool] Autostart of loop "${loop.name}" delivered but did not wake: ${result.reason ?? "unknown"}`);
|
|
75482
75641
|
} catch (error) {
|
|
75483
75642
|
console.error(`[LoopPool] Autostart of loop "${loop.name}" failed:`, error);
|
|
75484
75643
|
}
|
|
75644
|
+
}
|
|
75485
75645
|
return woken;
|
|
75486
75646
|
}
|
|
75487
75647
|
// ===========================================================================
|
|
@@ -75623,14 +75783,7 @@ var LoopPool = class _LoopPool {
|
|
|
75623
75783
|
dropLoopTimers(name15) {
|
|
75624
75784
|
let dropped = 0, kept = 0;
|
|
75625
75785
|
try {
|
|
75626
|
-
|
|
75627
|
-
if ((timer.loop ?? MAIN_LOOP) === name15) {
|
|
75628
|
-
if (timer.locked) {
|
|
75629
|
-
kept++;
|
|
75630
|
-
continue;
|
|
75631
|
-
}
|
|
75632
|
-
this.deps.workspace.deleteTimer(timer.id), dropped++;
|
|
75633
|
-
}
|
|
75786
|
+
({ dropped, kept } = dropTimersForLoop(this.deps.workspace, name15));
|
|
75634
75787
|
} catch (error) {
|
|
75635
75788
|
console.error(`[LoopPool] Failed to drop timers for loop "${name15}":`, error);
|
|
75636
75789
|
}
|
|
@@ -75741,7 +75894,7 @@ var LoopPool = class _LoopPool {
|
|
|
75741
75894
|
this.deps.compactionPrompt,
|
|
75742
75895
|
preLlmHookRunner
|
|
75743
75896
|
);
|
|
75744
|
-
callHandler?.attachSession(session);
|
|
75897
|
+
this.deps.basePromptSource && executor.setBasePromptSource(this.deps.basePromptSource), callHandler?.attachSession(session);
|
|
75745
75898
|
let modelHandler = callHandler ?? this.deps.adfCallHandler;
|
|
75746
75899
|
executor.setModelProviderFactory(modelHandler ? (model) => modelHandler.providerForModel(model) : null);
|
|
75747
75900
|
let runtime2 = new LoopRuntime({
|
|
@@ -76114,14 +76267,14 @@ function assembleAgent(options) {
|
|
|
76114
76267
|
options.compactionPrompt,
|
|
76115
76268
|
preLlmHookRunner
|
|
76116
76269
|
);
|
|
76117
|
-
executor.setModelProviderFactory(adfCallHandler ? (model) => adfCallHandler.providerForModel(model) : null), executor.recoverStaleTurnCheckpoint(), executor.reconcileOrphanedTasks(), validateConfigOnLoad(workspace, config);
|
|
76270
|
+
options.basePromptSource && executor.setBasePromptSource(options.basePromptSource), executor.setModelProviderFactory(adfCallHandler ? (model) => adfCallHandler.providerForModel(model) : null), executor.recoverStaleTurnCheckpoint(), executor.reconcileOrphanedTasks(), validateConfigOnLoad(workspace, config);
|
|
76118
76271
|
let snapshotConfig = config, refreshEffectiveRuntime = () => {
|
|
76119
76272
|
let sources = options.effectiveRuntime;
|
|
76120
76273
|
sources && recordEffectiveRuntime(workspace, () => buildEffectiveRuntime({
|
|
76121
76274
|
host: profile,
|
|
76122
76275
|
config: snapshotConfig,
|
|
76123
76276
|
provider: executor.getProvider() ?? provider,
|
|
76124
|
-
basePrompt:
|
|
76277
|
+
basePrompt: executor.getBasePrompt(),
|
|
76125
76278
|
toolPrompts: options.toolPrompts ?? {},
|
|
76126
76279
|
compactionPrompt: options.compactionPrompt,
|
|
76127
76280
|
sources,
|
|
@@ -76337,6 +76490,7 @@ ${json.slice(0, room)}${note}`;
|
|
|
76337
76490
|
// model override must follow it.
|
|
76338
76491
|
getProvider: () => executor.getProvider() ?? provider,
|
|
76339
76492
|
basePrompt: options.basePrompt ?? "",
|
|
76493
|
+
basePromptSource: options.basePromptSource,
|
|
76340
76494
|
toolPrompts: options.toolPrompts ?? {},
|
|
76341
76495
|
compactionPrompt: options.compactionPrompt,
|
|
76342
76496
|
adfCallHandler,
|
|
@@ -78424,18 +78578,69 @@ function createDefaultPipeline() {
|
|
|
78424
78578
|
}
|
|
78425
78579
|
|
|
78426
78580
|
// src/main/services/attestation.service.ts
|
|
78427
|
-
var REPLACEABLE_ROLES = ["owner", "operator"], RESERVED_ROLES = /* @__PURE__ */ new Set(["owner", "operator", "runtime", "clone", "rotation"]);
|
|
78581
|
+
var REPLACEABLE_ROLES = ["owner", "operator"], RESERVED_ROLES = /* @__PURE__ */ new Set(["owner", "operator", "runtime", "clone", "rotation"]), ATTESTATION_CLAIMS_MAX_BYTES = 4096, ATTESTATION_MAX_BYTES = 8192, PEER_ATTESTATIONS_MAX_COUNT = 64, PEER_ATTESTATIONS_MAX_BYTES = 65536, ATTESTATION_CLAIMS_MAX_DEPTH = 8;
|
|
78582
|
+
function attestationClaimsProblem(claims) {
|
|
78583
|
+
if (claims === null || typeof claims != "object" || Array.isArray(claims)) return "claims must be a JSON object";
|
|
78584
|
+
let problem = jsonValueProblem(claims, 1);
|
|
78585
|
+
if (problem) return problem;
|
|
78586
|
+
let bytes = Buffer.byteLength(canonicalJsonStringify(claims));
|
|
78587
|
+
return bytes > ATTESTATION_CLAIMS_MAX_BYTES ? `claims take ${bytes} bytes; the most is ${ATTESTATION_CLAIMS_MAX_BYTES}` : null;
|
|
78588
|
+
}
|
|
78589
|
+
function jsonValueProblem(value, depth) {
|
|
78590
|
+
if (value === null || typeof value == "string" || typeof value == "boolean") return null;
|
|
78591
|
+
if (typeof value == "number") return Number.isFinite(value) ? null : "claims numbers must be finite";
|
|
78592
|
+
if (typeof value != "object") return `claims cannot hold a ${typeof value}`;
|
|
78593
|
+
if (depth > ATTESTATION_CLAIMS_MAX_DEPTH) return `claims nest deeper than ${ATTESTATION_CLAIMS_MAX_DEPTH} levels`;
|
|
78594
|
+
if (Array.isArray(value)) {
|
|
78595
|
+
for (let item of value) {
|
|
78596
|
+
let problem = jsonValueProblem(item, depth + 1);
|
|
78597
|
+
if (problem) return problem;
|
|
78598
|
+
}
|
|
78599
|
+
return null;
|
|
78600
|
+
}
|
|
78601
|
+
let proto = Object.getPrototypeOf(value);
|
|
78602
|
+
if (proto !== Object.prototype && proto !== null) return "claims can hold only plain objects";
|
|
78603
|
+
if (Object.prototype.hasOwnProperty.call(value, "__proto__")) return 'claims cannot hold a "__proto__" key';
|
|
78604
|
+
for (let item of Object.values(value)) {
|
|
78605
|
+
let problem = jsonValueProblem(item, depth + 1);
|
|
78606
|
+
if (problem) return problem;
|
|
78607
|
+
}
|
|
78608
|
+
return null;
|
|
78609
|
+
}
|
|
78610
|
+
function fieldsProblem(fields) {
|
|
78611
|
+
for (let key of ["issuer", "subject", "role", "issued_at"])
|
|
78612
|
+
if (typeof fields[key] != "string") return `${key} must be a string`;
|
|
78613
|
+
for (let key of ["expires_at", "scope"])
|
|
78614
|
+
if (fields[key] !== void 0 && typeof fields[key] != "string") return `${key} must be a string`;
|
|
78615
|
+
return Object.prototype.hasOwnProperty.call(fields, "__proto__") ? 'an attestation cannot hold a "__proto__" key' : null;
|
|
78616
|
+
}
|
|
78428
78617
|
function signableBytes(fields) {
|
|
78618
|
+
if (fields.v === 2) return Buffer.from(canonicalJsonStringify(fields));
|
|
78429
78619
|
let { issuer, subject, role, issued_at, expires_at, scope } = fields, signable = { issuer, subject, role, issued_at };
|
|
78430
78620
|
return expires_at !== void 0 && (signable.expires_at = expires_at), scope !== void 0 && (signable.scope = scope), Buffer.from(canonicalJsonStringify(signable));
|
|
78431
78621
|
}
|
|
78432
78622
|
function createAttestation(fields, privateKeyPkcs8) {
|
|
78433
|
-
let
|
|
78434
|
-
|
|
78623
|
+
let fieldProblem = fieldsProblem(fields);
|
|
78624
|
+
if (fieldProblem) throw new Error(`Attestation not signed: ${fieldProblem}`);
|
|
78625
|
+
if (fields.claims !== void 0) {
|
|
78626
|
+
let problem = attestationClaimsProblem(fields.claims);
|
|
78627
|
+
if (problem) throw new Error(`Attestation not signed: ${problem}`);
|
|
78628
|
+
}
|
|
78629
|
+
let unsigned = { v: 2, ...fields }, signature = `ed25519:${signEd25519(signableBytes(unsigned), privateKeyPkcs8)}`;
|
|
78630
|
+
return { ...unsigned, signature };
|
|
78435
78631
|
}
|
|
78436
78632
|
function verifyAttestation(att, opts) {
|
|
78437
|
-
if (!att || typeof att.signature != "string" || !att.signature.startsWith("ed25519:") ||
|
|
78438
|
-
if (att.
|
|
78633
|
+
if (!att || typeof att != "object" || typeof att.signature != "string" || !att.signature.startsWith("ed25519:") || fieldsProblem(att) || att.v !== void 0 && att.v !== 2) return !1;
|
|
78634
|
+
if (att.v === 2) {
|
|
78635
|
+
try {
|
|
78636
|
+
if (Buffer.byteLength(canonicalJsonStringify(att)) > ATTESTATION_MAX_BYTES) return !1;
|
|
78637
|
+
} catch {
|
|
78638
|
+
return !1;
|
|
78639
|
+
}
|
|
78640
|
+
if (att.claims !== void 0 && attestationClaimsProblem(att.claims)) return !1;
|
|
78641
|
+
}
|
|
78642
|
+
if (opts?.expectedSubject && att.subject !== opts.expectedSubject) return !1;
|
|
78643
|
+
if (att.expires_at !== void 0) {
|
|
78439
78644
|
let expires = Date.parse(att.expires_at);
|
|
78440
78645
|
if (Number.isNaN(expires) || expires <= (opts?.now ?? /* @__PURE__ */ new Date()).getTime()) return !1;
|
|
78441
78646
|
}
|
|
@@ -78473,26 +78678,72 @@ function addPeerAttestation(workspace, attestation, ownDid) {
|
|
|
78473
78678
|
return { ok: !1, error: `Attestation subject must be this agent's DID (${ownDid})` };
|
|
78474
78679
|
if (!verifyAttestation(attestation, { expectedSubject: ownDid }))
|
|
78475
78680
|
return { ok: !1, error: "Attestation signature is invalid or expired" };
|
|
78476
|
-
|
|
78681
|
+
let existing = readAdfAttestations(workspace);
|
|
78682
|
+
if (existing.some((a) => a.signature === attestation.signature))
|
|
78477
78683
|
return { ok: !0 };
|
|
78478
|
-
let
|
|
78479
|
-
|
|
78684
|
+
let peers = existing.filter((a) => !RESERVED_ROLES.has(a.role));
|
|
78685
|
+
if (peers.length >= PEER_ATTESTATIONS_MAX_COUNT)
|
|
78686
|
+
return { ok: !1, error: `This agent already keeps ${peers.length} peer attestations, the most it stores` };
|
|
78687
|
+
let peerBytes = peers.reduce((n, a) => n + Buffer.byteLength(JSON.stringify(a)), 0) + Buffer.byteLength(JSON.stringify(attestation));
|
|
78688
|
+
if (peerBytes > PEER_ATTESTATIONS_MAX_BYTES)
|
|
78689
|
+
return { ok: !1, error: `Storing it would take peer attestations to ${peerBytes} bytes; the most is ${PEER_ATTESTATIONS_MAX_BYTES}` };
|
|
78690
|
+
if (attestation.v === 2)
|
|
78691
|
+
workspace.getDatabase().insertAttestation(attestation);
|
|
78692
|
+
else {
|
|
78693
|
+
let { issuer, subject, issued_at, expires_at, scope, signature } = attestation;
|
|
78694
|
+
workspace.getDatabase().insertAttestation({ issuer, subject, role, issued_at, expires_at, scope, signature });
|
|
78695
|
+
}
|
|
78696
|
+
return { ok: !0 };
|
|
78480
78697
|
}
|
|
78481
78698
|
function issuePeerAttestation(workspace, fields, signingKeyPkcs8) {
|
|
78482
78699
|
let issuer = workspace.getDid();
|
|
78483
78700
|
if (!issuer) return { ok: !1, error: "This agent has no DID" };
|
|
78484
78701
|
let role = typeof fields.role == "string" ? fields.role.trim() : "";
|
|
78485
|
-
|
|
78702
|
+
if (!role) return { ok: !1, error: "Attestation role is required" };
|
|
78703
|
+
if (RESERVED_ROLES.has(role)) return { ok: !1, error: `Role "${role}" is reserved for the runtime` };
|
|
78704
|
+
if (typeof fields.subject != "string" || !didToPublicKey(fields.subject))
|
|
78705
|
+
return { ok: !1, error: "Subject must be a valid did:key identifier" };
|
|
78706
|
+
if (fields.subject === issuer) return { ok: !1, error: "An agent cannot attest to itself" };
|
|
78707
|
+
if (fields.expires_at !== void 0 && Number.isNaN(Date.parse(fields.expires_at)))
|
|
78708
|
+
return { ok: !1, error: "expires_at must be an ISO 8601 timestamp" };
|
|
78709
|
+
if (fields.claims !== void 0) {
|
|
78710
|
+
let problem = attestationClaimsProblem(fields.claims);
|
|
78711
|
+
if (problem) return { ok: !1, error: problem };
|
|
78712
|
+
}
|
|
78713
|
+
return { ok: !0, attestation: createAttestation(
|
|
78486
78714
|
{
|
|
78487
78715
|
issuer,
|
|
78488
78716
|
subject: fields.subject,
|
|
78489
78717
|
role,
|
|
78490
78718
|
issued_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
78491
78719
|
...fields.expires_at !== void 0 ? { expires_at: fields.expires_at } : {},
|
|
78492
|
-
...fields.scope !== void 0 ? { scope: String(fields.scope) } : {}
|
|
78720
|
+
...fields.scope !== void 0 ? { scope: String(fields.scope) } : {},
|
|
78721
|
+
...fields.claims !== void 0 ? { claims: fields.claims } : {}
|
|
78493
78722
|
},
|
|
78494
78723
|
signingKeyPkcs8
|
|
78495
|
-
) }
|
|
78724
|
+
) };
|
|
78725
|
+
}
|
|
78726
|
+
function upgradeOwnAttestations(workspace, signers, busyTimeoutMs) {
|
|
78727
|
+
let keys = new Map(signers.filter((s) => s.did && s.privateKey).map((s) => [s.did, s.privateKey]));
|
|
78728
|
+
if (keys.size === 0) return 0;
|
|
78729
|
+
let updates = [];
|
|
78730
|
+
for (let att of readAdfAttestations(workspace)) {
|
|
78731
|
+
let key = att.v === void 0 ? keys.get(att.issuer) : void 0;
|
|
78732
|
+
if (!key || !verifyAttestation(att, { now: /* @__PURE__ */ new Date(0) })) continue;
|
|
78733
|
+
let { issuer, subject, role, issued_at, expires_at, scope } = att;
|
|
78734
|
+
updates.push({
|
|
78735
|
+
from: att.signature,
|
|
78736
|
+
to: createAttestation({
|
|
78737
|
+
issuer,
|
|
78738
|
+
subject,
|
|
78739
|
+
role,
|
|
78740
|
+
issued_at,
|
|
78741
|
+
...expires_at !== void 0 ? { expires_at } : {},
|
|
78742
|
+
...scope !== void 0 ? { scope } : {}
|
|
78743
|
+
}, key)
|
|
78744
|
+
});
|
|
78745
|
+
}
|
|
78746
|
+
return updates.length === 0 ? 0 : workspace.immediateTransaction(() => workspace.getDatabase().resignAttestations(updates), busyTimeoutMs);
|
|
78496
78747
|
}
|
|
78497
78748
|
function issueOwnerAttestation(workspace, keys) {
|
|
78498
78749
|
let subject = workspace.getDid();
|
|
@@ -79245,7 +79496,8 @@ var EXCLUDED_TOOLS = /* @__PURE__ */ new Set(["say", "ask"]), CODE_EXECUTION_MET
|
|
|
79245
79496
|
subject: input.subject,
|
|
79246
79497
|
role: input.role,
|
|
79247
79498
|
scope: input.scope,
|
|
79248
|
-
expires_at: input.expires_at
|
|
79499
|
+
expires_at: input.expires_at,
|
|
79500
|
+
...input.claims !== void 0 ? { claims: input.claims } : {}
|
|
79249
79501
|
}, signingKey);
|
|
79250
79502
|
return result.ok ? (this.logCall("info", "attestation_issue", input.role, `Issued "${input.role}" attestation for ${input.subject}`), { result: result.attestation }) : (this.logCall("warn", "attestation_issue", input.role, `Rejected: ${result.error}`), { error: result.error, errorCode: "INVALID_INPUT" });
|
|
79251
79503
|
} catch (err) {
|
|
@@ -79503,14 +79755,16 @@ var EXCLUDED_TOOLS = /* @__PURE__ */ new Set(["say", "ask"]), CODE_EXECUTION_MET
|
|
|
79503
79755
|
properties: {
|
|
79504
79756
|
attestation: {
|
|
79505
79757
|
type: "object",
|
|
79506
|
-
description: "The complete signed attestation object, exactly as returned by the issuer's attestation_issue",
|
|
79758
|
+
description: "The complete signed attestation object, exactly as returned by the issuer's attestation_issue (v2 signs every field, so pass it unchanged)",
|
|
79507
79759
|
properties: {
|
|
79760
|
+
v: { type: "number", description: "Format version: 2 for certs issued now (every field signed); absent on older v1 certs" },
|
|
79508
79761
|
issuer: { type: "string", description: "DID of the signer" },
|
|
79509
79762
|
subject: { type: "string", description: "This agent's DID" },
|
|
79510
79763
|
role: { type: "string", description: 'What the issuer asserts (e.g. "member", "reviewer") \u2014 reserved roles rejected' },
|
|
79511
79764
|
issued_at: { type: "string", description: "ISO 8601 timestamp" },
|
|
79512
79765
|
expires_at: { type: "string", description: "Optional ISO 8601 expiry" },
|
|
79513
79766
|
scope: { type: "string", description: "Optional qualifier (e.g. group or project identifier)" },
|
|
79767
|
+
claims: { type: "object", description: "Optional JSON the issuer signed with the cert" },
|
|
79514
79768
|
signature: { type: "string", description: "Issuer's Ed25519 signature over the canonical payload" }
|
|
79515
79769
|
},
|
|
79516
79770
|
required: ["issuer", "subject", "role", "issued_at", "signature"]
|
|
@@ -79528,7 +79782,8 @@ var EXCLUDED_TOOLS = /* @__PURE__ */ new Set(["say", "ask"]), CODE_EXECUTION_MET
|
|
|
79528
79782
|
subject: { type: "string", description: "DID of the agent being attested (did:key:..., not this agent)" },
|
|
79529
79783
|
role: { type: "string", description: 'What is being asserted (e.g. "member", "reviewer") \u2014 reserved roles rejected' },
|
|
79530
79784
|
scope: { type: "string", description: "Optional qualifier (e.g. group or project identifier)" },
|
|
79531
|
-
expires_at: { type: "string", description: "Optional ISO 8601 expiry" }
|
|
79785
|
+
expires_at: { type: "string", description: "Optional ISO 8601 expiry" },
|
|
79786
|
+
claims: { type: "object", description: 'Optional JSON object signed with the cert (at most 4096 bytes as canonical JSON, 8 levels deep, plain JSON values only). The runtime does not interpret it; namespace the keys, e.g. {"org.example/membership": {"tier": "editor"}}' }
|
|
79532
79787
|
},
|
|
79533
79788
|
required: ["subject", "role"]
|
|
79534
79789
|
}
|
|
@@ -79700,7 +79955,7 @@ if (typeof ${fnName} === 'function') {
|
|
|
79700
79955
|
let { event } = dispatch, triggerName = Object.entries(TRIGGER_TO_EVENT_TYPE).find(([, v]) => v === event.type)?.[0] ?? event.type;
|
|
79701
79956
|
console.log(`[Shell] Executing trigger command: "${command}" (trigger: ${event.type})`);
|
|
79702
79957
|
try {
|
|
79703
|
-
let { parse: parse2 } = await import("./parser-7GARNT5L.mjs"), { executeNode: executeNode2 } = await import("./pipeline-executor-
|
|
79958
|
+
let { parse: parse2 } = await import("./parser-7GARNT5L.mjs"), { executeNode: executeNode2 } = await import("./pipeline-executor-DRYEEFDR.mjs"), { EnvironmentResolver: EnvironmentResolver2 } = await import("./environment-R47X44GM.mjs"), config = this.workspace.getAgentConfig(), env = new EnvironmentResolver2(config, this.workspace);
|
|
79704
79959
|
env.setTriggerContext(dispatch);
|
|
79705
79960
|
let toolRegistry = this.adfCallHandler.getToolRegistry(), ast = parse2(command), startTime = performance.now(), result = await executeNode2(ast, "", {
|
|
79706
79961
|
workspace: this.workspace,
|
|
@@ -83793,6 +84048,7 @@ var MCP_CONNECT_BUDGET_MS = 25e3, AgentRuntimeBuilder = class {
|
|
|
83793
84048
|
...this.settings ? { effectiveRuntime: { settings: this.settings } } : {},
|
|
83794
84049
|
restoreLoop: opts.restoreLoop,
|
|
83795
84050
|
basePrompt: opts.prompts ? opts.prompts.basePrompt : this.basePrompt,
|
|
84051
|
+
basePromptSource: opts.prompts?.basePromptSource,
|
|
83796
84052
|
toolPrompts: opts.prompts ? opts.prompts.toolPrompts : this.toolPrompts,
|
|
83797
84053
|
compactionPrompt: opts.prompts ? opts.prompts.compactionPrompt : this.compactionPrompt,
|
|
83798
84054
|
adfCallHandler,
|
|
@@ -84698,6 +84954,73 @@ function applyBackgroundEvent(target, filePath, event, emit, now) {
|
|
|
84698
84954
|
Object.assign(target, step.patch), step.event && emit(step.event);
|
|
84699
84955
|
}
|
|
84700
84956
|
|
|
84957
|
+
// src/main/runtime/owner-command.ts
|
|
84958
|
+
init_execution_context();
|
|
84959
|
+
init_emit_umbilical();
|
|
84960
|
+
var OwnerCommandRefusedError = class extends Error {
|
|
84961
|
+
constructor(message, statusCode, code) {
|
|
84962
|
+
super(message);
|
|
84963
|
+
this.statusCode = statusCode;
|
|
84964
|
+
this.code = code;
|
|
84965
|
+
this.name = "OwnerCommandRefusedError";
|
|
84966
|
+
}
|
|
84967
|
+
statusCode;
|
|
84968
|
+
code;
|
|
84969
|
+
};
|
|
84970
|
+
async function runOwnerCommand(host2, req) {
|
|
84971
|
+
if (!req || typeof req.name != "string" || typeof req.args != "string" || req.args.length > 4096 || /[\r\n]/.test(req.args) || typeof req.authorize != "boolean" || req.loop !== void 0 && typeof req.loop != "string" || req.requestId !== void 0 && (typeof req.requestId != "string" || !/^[A-Za-z0-9_-]{1,64}$/.test(req.requestId)))
|
|
84972
|
+
throw new OwnerCommandRefusedError("Invalid command request: args must be a single line of at most 4096 characters and requestId must use 1\u201364 letters, digits, underscores or hyphens.", 400, "invalid_request");
|
|
84973
|
+
let id = req.requestId ?? "cmd_" + nanoid(10), loop = req.loop || MAIN_LOOP;
|
|
84974
|
+
if (!host2.loopPool.hasLoop(loop)) throw new OwnerCommandRefusedError(`No loop named "${loop}" on this agent.`, 404, "loop_not_found");
|
|
84975
|
+
let runtime2 = loop === MAIN_LOOP ? null : host2.loopPool.getRuntime(loop), executor = loop === MAIN_LOOP ? host2.executor : runtime2?.executor, handler = loop === MAIN_LOOP ? host2.adfCallHandler : runtime2?.callHandler, workspace = loop === MAIN_LOOP ? host2.workspace : runtime2?.workspace;
|
|
84976
|
+
if (!executor || !workspace) throw new OwnerCommandRefusedError(`Loop "${loop}" is not running (it is disabled or stopping). Enable it, then run the command again.`, 409, "loop_not_running");
|
|
84977
|
+
if (executor.getState() === "stopped") throw new OwnerCommandRefusedError(`Agent is off. Start it, then run /${req.name} again.`, 409, "agent_not_running");
|
|
84978
|
+
let sandbox = host2.codeSandboxService;
|
|
84979
|
+
if (!sandbox || !handler) throw new OwnerCommandRefusedError("This runtime has no code sandbox, so agent commands cannot run here.", 409, "code_execution_unavailable");
|
|
84980
|
+
let config = host2.workspace.getAgentConfig(), command = Array.isArray(config.commands) ? config.commands.find((c) => c && typeof c == "object" && c.name === req.name) : void 0;
|
|
84981
|
+
if (!command) throw new OwnerCommandRefusedError(`No command "/${req.name}" on this agent. Add it under Commands in the agent's config.`, 404, "command_not_found");
|
|
84982
|
+
let lambda = typeof command.lambda == "string" ? command.lambda : JSON.stringify(command.lambda) ?? "undefined", started = performance.now(), status = "error", authorized = !1, body;
|
|
84983
|
+
try {
|
|
84984
|
+
let ref = parseLambdaRef(lambda);
|
|
84985
|
+
if ("error" in ref) throw new Error(ref.error);
|
|
84986
|
+
let { file, fn } = ref, source = await loadLambdaSource((p) => workspace.readFile(p), file);
|
|
84987
|
+
if (source === null) throw new Error(`Lambda file "${file}" not found. Fix commands[].lambda for /${req.name} or create the file.`);
|
|
84988
|
+
authorized = req.authorize === !0 || workspace.isFileAuthorized(file);
|
|
84989
|
+
let args2 = splitArgv(req.args).join(" "), invocation = { command: req.name, args: args2, argv: splitArgv(args2), invoker: "owner", loop, authorized, id }, missing = `Function "${fn}" not found in "${file}". Declare it at the top level, or fix commands[].lambda for /${req.name}.`, wrapped = `${transformExports(transformImports(source))}
|
|
84990
|
+
if (typeof ${fn} === 'function') { return await ${fn}(${JSON.stringify(invocation)}); }
|
|
84991
|
+
throw new Error(${JSON.stringify(missing)});`, sandboxId = `${config.id}:cmd:${file}:${id}:${nanoid(10)}`, payload = { lambda_path: file, function_name: fn, kind: "owner_command", command: req.name, loop, authorized };
|
|
84992
|
+
emitUmbilicalEvent({ event_type: "lambda.started", agentId: config.id, source: `lambda:${file}:${fn}`, payload });
|
|
84993
|
+
try {
|
|
84994
|
+
let run2 = () => sandbox.execute(
|
|
84995
|
+
sandboxId,
|
|
84996
|
+
wrapped,
|
|
84997
|
+
config.limits.execution_timeout_ms,
|
|
84998
|
+
(method, callArgs) => withAuthorization(authorized, () => handler.handleCall(method, callArgs)),
|
|
84999
|
+
{ enabledTools: handler.getEnabledToolNames(), hilTools: handler.getHilToolNames(), isAuthorized: authorized },
|
|
85000
|
+
{ handlerAuthorized: authorized, agent: config.id, ephemeral: !0 }
|
|
85001
|
+
), result = await withSource(`lambda:${file}:${fn}`, config.id, () => withLoop(loop, run2));
|
|
85002
|
+
status = result.error ? ["REQUIRES_AUTHORIZED_CODE", "REQUIRES_AUTHORIZED_CALLER", "PROTECTION_DENIED"].includes(result.errorCode ?? "") ? "denied" : "error" : "ok", body = result.error ?? result.result ?? "(no return value)", result.stdout && (body += `
|
|
85003
|
+
|
|
85004
|
+
Output:
|
|
85005
|
+
${result.stdout}`), emitUmbilicalEvent({ event_type: result.error ? "lambda.failed" : "lambda.completed", agentId: config.id, source: `lambda:${file}:${fn}`, payload: { ...payload, duration_ms: performance.now() - started, ...result.error ? { error: result.error } : {} } });
|
|
85006
|
+
} catch (error) {
|
|
85007
|
+
throw emitUmbilicalEvent({ event_type: "lambda.failed", agentId: config.id, source: `lambda:${file}:${fn}`, payload: { ...payload, duration_ms: performance.now() - started, error: error instanceof Error ? error.message : String(error) } }), error;
|
|
85008
|
+
} finally {
|
|
85009
|
+
sandbox.destroy(sandboxId);
|
|
85010
|
+
}
|
|
85011
|
+
} catch (error) {
|
|
85012
|
+
body = error instanceof Error ? error.message : String(error);
|
|
85013
|
+
}
|
|
85014
|
+
let durationMs = +(performance.now() - started).toFixed(2);
|
|
85015
|
+
body = executor.boundToolResult(body, "/" + req.name);
|
|
85016
|
+
let args = splitArgv(req.args).join(" "), record = executor.recordOwnerCommand(formatOwnerCommandRow({ v: 1, id, command: "/" + req.name + (args ? " " + args : ""), lambda, authorized, status, duration_ms: durationMs }, body));
|
|
85017
|
+
try {
|
|
85018
|
+
workspace.insertLog(status === "ok" ? "info" : "error", "command", "run", "/" + req.name, `${status} (${durationMs}ms)`, { status, duration_ms: durationMs, authorized, loop });
|
|
85019
|
+
} catch {
|
|
85020
|
+
}
|
|
85021
|
+
return { id, name: req.name, loop, status, authorized, result: body, durationMs, ...record };
|
|
85022
|
+
}
|
|
85023
|
+
|
|
84701
85024
|
// src/main/runtime/interrupt-turn.ts
|
|
84702
85025
|
var InterruptRefusedError = class extends Error {
|
|
84703
85026
|
constructor(message, statusCode) {
|
|
@@ -84802,7 +85125,7 @@ function mcpServersWithSealedCredentials(workspace) {
|
|
|
84802
85125
|
return [];
|
|
84803
85126
|
}
|
|
84804
85127
|
}
|
|
84805
|
-
var DUPLICATE_AGENT_ID_CODE = "duplicate_agent_id", AGENT_NOT_RUNNING_CODE = "agent_not_running", DOCUMENT_HOLDER_FORMAT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, DOCUMENT_HOLD_TTL_MS = 6e4, RuntimeLoopError = class extends Error {
|
|
85128
|
+
var DUPLICATE_AGENT_ID_CODE = "duplicate_agent_id", AGENT_NOT_RUNNING_CODE = "agent_not_running", DOCUMENT_HOLDER_FORMAT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, DOCUMENT_HOLD_TTL_MS = 6e4, KILL_STOPPED_AUTOSTART = "A Kill stopped this autostart. Start the agent again.", RuntimeLoopError = class extends Error {
|
|
84806
85129
|
/** `details`: extra fields for the HTTP error body (e.g. `candidates`). */
|
|
84807
85130
|
constructor(message, statusCode, code, details) {
|
|
84808
85131
|
super(message);
|
|
@@ -84873,6 +85196,7 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
84873
85196
|
super(), this.settings = opts.settings, this.providerFactory = opts.providerFactory, this.basePrompt = opts.basePrompt ?? "", this.toolPrompts = opts.toolPrompts ?? {}, this.compactionPrompt = opts.compactionPrompt, this.agentRuntimeBuilder = opts.agentRuntimeBuilder, this.enforceReviewGate = opts.enforceReviewGate ?? !0, this.agentLeases = opts.agentLeases === void 0 ? processAgentLeases() : opts.agentLeases, this.documentHoldTtlMs = opts.documentHoldTtlMs ?? DOCUMENT_HOLD_TTL_MS, this.agentLeases?.addHostedPathsProbe(() => [...this.filePathToAgentId.keys(), ...this.inFlightLoads.keys()]);
|
|
84874
85197
|
}
|
|
84875
85198
|
async loadAgent(filePath, opts = {}) {
|
|
85199
|
+
if (RuntimeGate.killing) throw new RuntimeLoopError(KILL_IN_PROGRESS_ERROR, 409, "kill_in_progress");
|
|
84876
85200
|
let canonicalPath = this.canonicalFilePath(filePath), existingId = this.filePathToAgentId.get(canonicalPath);
|
|
84877
85201
|
if (existingId) return this.toRef(this.requireAgent(existingId));
|
|
84878
85202
|
let pending = this.inFlightLoads.get(canonicalPath);
|
|
@@ -84885,6 +85209,24 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
84885
85209
|
this.inFlightLoads.delete(canonicalPath), await this.agentLeases?.reconcile();
|
|
84886
85210
|
}
|
|
84887
85211
|
}
|
|
85212
|
+
/**
|
|
85213
|
+
* Waits for the loads in flight to finish (or fail), so a Kill can unload
|
|
85214
|
+
* what they registered. Answers the files still loading after `timeoutMs`:
|
|
85215
|
+
* a stuck load never holds up the rest of the Kill.
|
|
85216
|
+
*/
|
|
85217
|
+
async settleLoads(timeoutMs = 1e4) {
|
|
85218
|
+
let timer, timedOut = new Promise((resolve20) => {
|
|
85219
|
+
timer = setTimeout(resolve20, timeoutMs);
|
|
85220
|
+
}), settled = (async () => {
|
|
85221
|
+
for (; this.inFlightLoads.size > 0; ) await Promise.allSettled([...this.inFlightLoads.values()]);
|
|
85222
|
+
})();
|
|
85223
|
+
try {
|
|
85224
|
+
await Promise.race([settled, timedOut]);
|
|
85225
|
+
} finally {
|
|
85226
|
+
clearTimeout(timer);
|
|
85227
|
+
}
|
|
85228
|
+
return [...this.inFlightLoads.keys()];
|
|
85229
|
+
}
|
|
84888
85230
|
/**
|
|
84889
85231
|
* Resolves true once a load of `filePath` in flight has finished (or
|
|
84890
85232
|
* failed), at once when none is; false when it is still loading after
|
|
@@ -85350,6 +85692,7 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
85350
85692
|
* active-state greeting, as Studio's foreground start does.
|
|
85351
85693
|
*/
|
|
85352
85694
|
async startAgent(agentId, opts = {}) {
|
|
85695
|
+
if (RuntimeGate.killing) throw new RuntimeLoopError(KILL_IN_PROGRESS_ERROR, 409, "kill_in_progress");
|
|
85353
85696
|
RuntimeGate.resume();
|
|
85354
85697
|
let managed = this.requireAgent(agentId), lifecycle = managed.agent.getLifecycleState();
|
|
85355
85698
|
if (lifecycle !== "running")
|
|
@@ -85368,15 +85711,21 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
85368
85711
|
if (raced.status === "rejected") throw raced.err;
|
|
85369
85712
|
return raced.status === "resolved" ? raced.dispatched : !0;
|
|
85370
85713
|
}
|
|
85714
|
+
/**
|
|
85715
|
+
* `killEpoch`: RuntimeGate.killEpoch when the caller's start began (before
|
|
85716
|
+
* its own awaits); a Kill since then refuses the start.
|
|
85717
|
+
*/
|
|
85371
85718
|
async startOrLoadAgent(identifier, opts = {}) {
|
|
85372
|
-
let managed = this.resolveAgent(identifier), loaded = !1;
|
|
85719
|
+
let killEpoch = opts.killEpoch ?? RuntimeGate.killEpoch, managed = this.resolveAgent(identifier), loaded = !1;
|
|
85373
85720
|
if (!managed) {
|
|
85374
85721
|
let filePath = this.documents.resolve(identifier)?.filePath ?? this.findAgentFile(identifier);
|
|
85375
85722
|
if (!filePath) throw new Error(`RuntimeService: unknown agent "${identifier}"`);
|
|
85376
85723
|
let ref = await this.loadAgent(filePath);
|
|
85377
85724
|
managed = this.requireAgent(ref.id), loaded = !0;
|
|
85378
85725
|
}
|
|
85379
|
-
|
|
85726
|
+
if (RuntimeGate.killedSince(killEpoch))
|
|
85727
|
+
throw loaded && await this.unloadAgent(managed.id, { mode: "immediate" }), new RuntimeLoopError(KILL_IN_PROGRESS_ERROR, 409, "kill_in_progress");
|
|
85728
|
+
let startupTriggered = await this.startAgent(managed.id, { hasUserMessage: opts.hasUserMessage });
|
|
85380
85729
|
return {
|
|
85381
85730
|
ref: this.toRef(managed),
|
|
85382
85731
|
loaded,
|
|
@@ -85423,7 +85772,16 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
85423
85772
|
throw err instanceof InterruptRefusedError ? new RuntimeLoopError(err.message, err.statusCode) : err;
|
|
85424
85773
|
}
|
|
85425
85774
|
}
|
|
85775
|
+
async runAgentCommand(agentId, name15, body) {
|
|
85776
|
+
let managed = this.requireAgent(agentId);
|
|
85777
|
+
try {
|
|
85778
|
+
return await runOwnerCommand(managed.agent, { ...body, name: name15, args: body.args ?? "", authorize: body.authorize === !0 });
|
|
85779
|
+
} catch (err) {
|
|
85780
|
+
throw err instanceof OwnerCommandRefusedError ? new RuntimeLoopError(err.message, err.statusCode, err.code) : err;
|
|
85781
|
+
}
|
|
85782
|
+
}
|
|
85426
85783
|
async autostartFromDirectories(trackedDirs2, opts = {}) {
|
|
85784
|
+
let killEpoch = RuntimeGate.killEpoch;
|
|
85427
85785
|
RuntimeGate.resume();
|
|
85428
85786
|
let files = await this.scanAdfFilesAsync(trackedDirs2, opts.maxDepth ?? 5), report = {
|
|
85429
85787
|
scanned: files.length,
|
|
@@ -85454,7 +85812,11 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
85454
85812
|
if (!isConfigReviewed(this.settings?.get("reviewedAgents"), bootResult.config))
|
|
85455
85813
|
return { kind: "skipped", entry: { filePath, name: name15, reason: "unreviewed", agentId: boot.agentId } };
|
|
85456
85814
|
try {
|
|
85457
|
-
|
|
85815
|
+
if (RuntimeGate.killedSince(killEpoch)) throw new RuntimeLoopError(KILL_STOPPED_AUTOSTART, 409, "kill_in_progress");
|
|
85816
|
+
let ref = await this.loadAgent(filePath, { enforceReviewGate: !1 });
|
|
85817
|
+
if (RuntimeGate.killedSince(killEpoch))
|
|
85818
|
+
throw await this.unloadAgent(ref.id, { mode: "immediate" }), new RuntimeLoopError(KILL_STOPPED_AUTOSTART, 409, "kill_in_progress");
|
|
85819
|
+
let startupTriggered = await this.startAgent(ref.id);
|
|
85458
85820
|
return { kind: "started", entry: { agentId: ref.id, filePath, name: ref.config.name, startupTriggered } };
|
|
85459
85821
|
} catch (err) {
|
|
85460
85822
|
return err instanceof RuntimeReviewRequiredError ? { kind: "skipped", entry: { filePath, name: name15, reason: "unreviewed", agentId: err.agentId } } : err instanceof RuntimeLoopError && err.code === AGENT_LEASED_CODE ? (console.warn(`[RuntimeService] Autostart skipped: ${err.message}`), { kind: "skipped", entry: { filePath, name: name15, reason: "leased_elsewhere", agentId: boot.agentId, message: err.message } }) : {
|
|
@@ -85994,7 +86356,7 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
85994
86356
|
effectiveTools: null
|
|
85995
86357
|
}, side = (config.loops ?? []).map((loop) => ({
|
|
85996
86358
|
name: loop.name,
|
|
85997
|
-
goal: loop.goal,
|
|
86359
|
+
goal: loop.goal ?? "",
|
|
85998
86360
|
status: "idle",
|
|
85999
86361
|
enabled: loop.enabled !== !1,
|
|
86000
86362
|
isMain: !1,
|
|
@@ -86011,7 +86373,7 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
86011
86373
|
if (pool.hasLoop(input.name)) throw new RuntimeLoopError(`A loop named "${input.name}" already exists.`, 409);
|
|
86012
86374
|
let host2 = managed.agent.workspace.getAgentConfig(), available = new Set(listAvailableLoopTools(host2)), candidate = {
|
|
86013
86375
|
name: input.name,
|
|
86014
|
-
goal: input.goal,
|
|
86376
|
+
...input.goal !== void 0 ? { goal: input.goal } : {},
|
|
86015
86377
|
enabled: input.enabled ?? !0,
|
|
86016
86378
|
autostart: input.autostart ?? !0,
|
|
86017
86379
|
...input.autonomous !== void 0 ? { autonomous: input.autonomous } : {},
|
|
@@ -86128,7 +86490,9 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
86128
86490
|
let target = this.requireTarget(agentId);
|
|
86129
86491
|
if (this.assertBaseRevision("config", configRevision(target.workspace), opts.baseRevision, null), !target.managed) {
|
|
86130
86492
|
let doc = target.doc;
|
|
86131
|
-
stripLoopNameMarker(config)
|
|
86493
|
+
stripLoopNameMarker(config);
|
|
86494
|
+
let previousConfig2 = doc.workspace.getAgentConfig();
|
|
86495
|
+
doc.workspace.setAgentConfig(config), await teardownRemovedLoopsOffline(doc.workspace, previousConfig2, config), doc.config = config, doc.configWrites++;
|
|
86132
86496
|
let revision2 = configRevision(doc.workspace, currentResourceWriter()).revision, rename2 = this.syncAgentFileToName(doc.filePath, config.name);
|
|
86133
86497
|
return {
|
|
86134
86498
|
agentId: target.id,
|
|
@@ -87127,6 +87491,7 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
87127
87491
|
registerAgent(agent, filePath, config, idOverride, keyCell = { current: null }) {
|
|
87128
87492
|
if (RuntimeGate.tearingDown)
|
|
87129
87493
|
throw new Error("RuntimeService: runtime teardown in progress \u2014 agent not registered.");
|
|
87494
|
+
if (RuntimeGate.killing) throw new RuntimeLoopError(KILL_IN_PROGRESS_ERROR, 409, "kill_in_progress");
|
|
87130
87495
|
let id = idOverride ?? config.id;
|
|
87131
87496
|
this.assertNoDuplicateId(id, filePath);
|
|
87132
87497
|
let managed = {
|
|
@@ -87505,6 +87870,7 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
|
|
|
87505
87870
|
let base = this.settings?.get("globalSystemPrompt"), tools = this.settings?.get("toolPrompts"), compaction = this.settings?.get("compactionPrompt");
|
|
87506
87871
|
return {
|
|
87507
87872
|
basePrompt: typeof base == "string" ? base : this.basePrompt,
|
|
87873
|
+
...this.settings ? { basePromptSource: () => this.settings?.get("globalSystemPrompt") } : {},
|
|
87508
87874
|
toolPrompts: tools && typeof tools == "object" && !Array.isArray(tools) ? tools : this.toolPrompts,
|
|
87509
87875
|
compactionPrompt: typeof compaction == "string" ? compaction : this.compactionPrompt
|
|
87510
87876
|
};
|
|
@@ -109134,6 +109500,70 @@ data: {"cursor":13,"kind":"executor","agentId":"\u2026","filePath":"/agents/agen
|
|
|
109134
109500
|
}
|
|
109135
109501
|
]
|
|
109136
109502
|
}
|
|
109503
|
+
},
|
|
109504
|
+
"/agents/{id}/commands/{name}/run": {
|
|
109505
|
+
post: {
|
|
109506
|
+
tags: [
|
|
109507
|
+
"Loops"
|
|
109508
|
+
],
|
|
109509
|
+
summary: "Run an owner slash command",
|
|
109510
|
+
description: "Runs a registered lambda without a model turn and records its bounded outcome in the selected loop. Requires a running agent; never starts it. Error and denied outcomes are recorded and return 200. The authorize boolean elevates only this invocation; chat text is never interpreted as a command.",
|
|
109511
|
+
operationId: "runAgentCommand",
|
|
109512
|
+
parameters: [
|
|
109513
|
+
{
|
|
109514
|
+
$ref: "#/components/parameters/AgentIdPath"
|
|
109515
|
+
},
|
|
109516
|
+
{
|
|
109517
|
+
name: "name",
|
|
109518
|
+
in: "path",
|
|
109519
|
+
required: !0,
|
|
109520
|
+
description: "Registered command name without the slash.",
|
|
109521
|
+
schema: {
|
|
109522
|
+
type: "string"
|
|
109523
|
+
}
|
|
109524
|
+
}
|
|
109525
|
+
],
|
|
109526
|
+
requestBody: {
|
|
109527
|
+
required: !1,
|
|
109528
|
+
content: {
|
|
109529
|
+
"application/json": {
|
|
109530
|
+
schema: {
|
|
109531
|
+
$ref: "#/components/schemas/OwnerCommandBody"
|
|
109532
|
+
}
|
|
109533
|
+
}
|
|
109534
|
+
}
|
|
109535
|
+
},
|
|
109536
|
+
responses: {
|
|
109537
|
+
"400": {
|
|
109538
|
+
$ref: "#/components/responses/BadRequest"
|
|
109539
|
+
},
|
|
109540
|
+
"401": {
|
|
109541
|
+
$ref: "#/components/responses/Unauthorized"
|
|
109542
|
+
},
|
|
109543
|
+
"403": {
|
|
109544
|
+
$ref: "#/components/responses/Forbidden"
|
|
109545
|
+
},
|
|
109546
|
+
"404": {
|
|
109547
|
+
$ref: "#/components/responses/NotFound"
|
|
109548
|
+
},
|
|
109549
|
+
"409": {
|
|
109550
|
+
$ref: "#/components/responses/Conflict"
|
|
109551
|
+
},
|
|
109552
|
+
"500": {
|
|
109553
|
+
$ref: "#/components/responses/ServerError"
|
|
109554
|
+
},
|
|
109555
|
+
"200": {
|
|
109556
|
+
description: "Recorded command outcome",
|
|
109557
|
+
content: {
|
|
109558
|
+
"application/json": {
|
|
109559
|
+
schema: {
|
|
109560
|
+
$ref: "#/components/schemas/OwnerCommandResult"
|
|
109561
|
+
}
|
|
109562
|
+
}
|
|
109563
|
+
}
|
|
109564
|
+
}
|
|
109565
|
+
}
|
|
109566
|
+
}
|
|
109137
109567
|
}
|
|
109138
109568
|
},
|
|
109139
109569
|
components: {
|
|
@@ -110949,8 +111379,27 @@ data: {"cursor":13,"kind":"executor","agentId":"\u2026","filePath":"/agents/agen
|
|
|
110949
111379
|
additionalProperties: {
|
|
110950
111380
|
type: "object",
|
|
110951
111381
|
properties: {
|
|
110952
|
-
support: {
|
|
110953
|
-
|
|
111382
|
+
support: {
|
|
111383
|
+
type: "object",
|
|
111384
|
+
properties: {
|
|
111385
|
+
image: {
|
|
111386
|
+
type: "boolean"
|
|
111387
|
+
},
|
|
111388
|
+
audio: {
|
|
111389
|
+
type: "boolean"
|
|
111390
|
+
},
|
|
111391
|
+
video: {
|
|
111392
|
+
type: "boolean"
|
|
111393
|
+
}
|
|
111394
|
+
}
|
|
111395
|
+
},
|
|
111396
|
+
refusals: {
|
|
111397
|
+
type: "object",
|
|
111398
|
+
additionalProperties: {
|
|
111399
|
+
type: "string"
|
|
111400
|
+
},
|
|
111401
|
+
description: "Why each modality not in support is refused, keyed image, audio or video."
|
|
111402
|
+
}
|
|
110954
111403
|
}
|
|
110955
111404
|
},
|
|
110956
111405
|
description: "GET /agents/{id}/status of a running agent: each loop's effective media (main and live inner loops, keyed by loop name): what its provider connector carries, narrowed by the agent's model.multimodal toggles. POST /agents/{id}/chat refuses the rest with 400 media_unsupported."
|
|
@@ -123623,6 +124072,79 @@ data: {"cursor":13,"kind":"executor","agentId":"\u2026","filePath":"/agents/agen
|
|
|
123623
124072
|
}
|
|
123624
124073
|
}
|
|
123625
124074
|
]
|
|
124075
|
+
},
|
|
124076
|
+
OwnerCommandBody: {
|
|
124077
|
+
type: "object",
|
|
124078
|
+
properties: {
|
|
124079
|
+
args: {
|
|
124080
|
+
type: "string",
|
|
124081
|
+
maxLength: 4096,
|
|
124082
|
+
pattern: "^[^\\n]*$",
|
|
124083
|
+
default: ""
|
|
124084
|
+
},
|
|
124085
|
+
loop: {
|
|
124086
|
+
type: "string",
|
|
124087
|
+
default: "main"
|
|
124088
|
+
},
|
|
124089
|
+
authorize: {
|
|
124090
|
+
type: "boolean",
|
|
124091
|
+
default: !1,
|
|
124092
|
+
description: "Owner grant for this invocation only. Paired devices may grant it."
|
|
124093
|
+
},
|
|
124094
|
+
requestId: {
|
|
124095
|
+
type: "string",
|
|
124096
|
+
pattern: "^[A-Za-z0-9_-]{1,64}$"
|
|
124097
|
+
}
|
|
124098
|
+
}
|
|
124099
|
+
},
|
|
124100
|
+
OwnerCommandResult: {
|
|
124101
|
+
type: "object",
|
|
124102
|
+
required: [
|
|
124103
|
+
"id",
|
|
124104
|
+
"name",
|
|
124105
|
+
"loop",
|
|
124106
|
+
"status",
|
|
124107
|
+
"authorized",
|
|
124108
|
+
"result",
|
|
124109
|
+
"durationMs",
|
|
124110
|
+
"deferred"
|
|
124111
|
+
],
|
|
124112
|
+
properties: {
|
|
124113
|
+
id: {
|
|
124114
|
+
type: "string"
|
|
124115
|
+
},
|
|
124116
|
+
name: {
|
|
124117
|
+
type: "string"
|
|
124118
|
+
},
|
|
124119
|
+
loop: {
|
|
124120
|
+
type: "string"
|
|
124121
|
+
},
|
|
124122
|
+
status: {
|
|
124123
|
+
type: "string",
|
|
124124
|
+
enum: [
|
|
124125
|
+
"ok",
|
|
124126
|
+
"error",
|
|
124127
|
+
"denied"
|
|
124128
|
+
]
|
|
124129
|
+
},
|
|
124130
|
+
authorized: {
|
|
124131
|
+
type: "boolean"
|
|
124132
|
+
},
|
|
124133
|
+
result: {
|
|
124134
|
+
type: "string",
|
|
124135
|
+
description: "Bounded output exactly as recorded in the loop."
|
|
124136
|
+
},
|
|
124137
|
+
durationMs: {
|
|
124138
|
+
type: "number"
|
|
124139
|
+
},
|
|
124140
|
+
deferred: {
|
|
124141
|
+
type: "boolean",
|
|
124142
|
+
description: "The record waits for the current step to finish."
|
|
124143
|
+
},
|
|
124144
|
+
seq: {
|
|
124145
|
+
type: "integer"
|
|
124146
|
+
}
|
|
124147
|
+
}
|
|
123626
124148
|
}
|
|
123627
124149
|
}
|
|
123628
124150
|
}
|
|
@@ -126198,6 +126720,18 @@ function rotateDaemonEncKey(settingsDir) {
|
|
|
126198
126720
|
return { key: ensureDaemonEncKey(settingsDir), retiredLabel: current.label };
|
|
126199
126721
|
}
|
|
126200
126722
|
|
|
126723
|
+
// src/main/services/secret-storage-policy.ts
|
|
126724
|
+
var SECRET_STORAGE_POLICY_KEY = "secretStoragePolicy";
|
|
126725
|
+
var SETTINGS_SECRET_KEYS = ["ownerMnemonic", "runtimePrivateKey", "runtimeEncPrivateKey", "mcpOauthCredentials"], SUPERSEDED_MNEMONIC_PREFIX = "ownerMnemonicSuperseded:";
|
|
126726
|
+
function isSecretSettingsKey(key) {
|
|
126727
|
+
return SETTINGS_SECRET_KEYS.includes(key) || key.startsWith(SUPERSEDED_MNEMONIC_PREFIX);
|
|
126728
|
+
}
|
|
126729
|
+
var SecretStorageRefusedError = class extends Error {
|
|
126730
|
+
constructor(message) {
|
|
126731
|
+
super(message), this.name = "SecretStorageRefusedError";
|
|
126732
|
+
}
|
|
126733
|
+
};
|
|
126734
|
+
|
|
126201
126735
|
// src/main/services/owner-identity.service.ts
|
|
126202
126736
|
var OWNER_SEED_DERIVED_KEY = "ownerDidSeedDerived";
|
|
126203
126737
|
function ownerMnemonicSupersededKey(ownerDid) {
|
|
@@ -126294,6 +126828,11 @@ var OwnerIdentityService = class {
|
|
|
126294
126828
|
}
|
|
126295
126829
|
return this.settings.setSecret("ownerMnemonic", phrase), currentOwnerDid || (this.settings.set("ownerDid", owner.did), this.settings.set("ownerSeedBackupConfirmed", !1)), this.markSeedDerived(), console.log(opts.replacingStale ? `[OwnerIdentity] The owner is now ${owner.did} (switched outside this app, e.g. adf identity import): replaced this install's phrase of the previous owner with the one in the OS keychain` : `[OwnerIdentity] Imported owner phrase for ${owner.did} from the OS keychain`), phrase;
|
|
126296
126830
|
}
|
|
126831
|
+
/** Throws when secrets cannot be saved right now (Studio's secret-storage choice), before any write. */
|
|
126832
|
+
assertSecretsWritable() {
|
|
126833
|
+
let refusal = this.settings.secretWriteRefusal?.() ?? null;
|
|
126834
|
+
if (refusal) throw new SecretStorageRefusedError(refusal);
|
|
126835
|
+
}
|
|
126297
126836
|
// =========================================================================
|
|
126298
126837
|
// Identity bootstrap + migration
|
|
126299
126838
|
// =========================================================================
|
|
@@ -126343,6 +126882,7 @@ var OwnerIdentityService = class {
|
|
|
126343
126882
|
runtimeDid: this.settings.get("runtimeDid") ?? "",
|
|
126344
126883
|
migrated: !1
|
|
126345
126884
|
};
|
|
126885
|
+
this.assertSecretsWritable();
|
|
126346
126886
|
let isUpgrade = !!existingOwnerDid;
|
|
126347
126887
|
if (isUpgrade) {
|
|
126348
126888
|
let legacyOwner = this.settings.get("legacyOwnerDids") ?? [];
|
|
@@ -126419,11 +126959,23 @@ var OwnerIdentityService = class {
|
|
|
126419
126959
|
let runtimeDid = this.getRuntimeDid();
|
|
126420
126960
|
if (!runtimeDid || keyStatus === "absent") return this.mintRuntimeKey(ownerKey, ownerDid);
|
|
126421
126961
|
let delegation = this.getRuntimeDelegation();
|
|
126422
|
-
return (!delegation || delegation.issuer !== ownerDid || !verifyAttestation(delegation, { expectedSubject: runtimeDid })) && this.settings.set("runtimeDelegation", createAttestation(
|
|
126962
|
+
return (!delegation || delegation.v !== 2 || delegation.issuer !== ownerDid || !verifyAttestation(delegation, { expectedSubject: runtimeDid })) && this.settings.set("runtimeDelegation", createAttestation(
|
|
126423
126963
|
{ issuer: ownerDid, subject: runtimeDid, role: "runtime", issued_at: (/* @__PURE__ */ new Date()).toISOString() },
|
|
126424
126964
|
ownerKey
|
|
126425
126965
|
)), runtimeDid;
|
|
126426
126966
|
}
|
|
126967
|
+
/** Own v1 attestations in the file re-signed as v2 (attestation.service.ts). Logged, never thrown. */
|
|
126968
|
+
upgradeAttestations(workspace) {
|
|
126969
|
+
try {
|
|
126970
|
+
let upgraded = upgradeOwnAttestations(workspace, [
|
|
126971
|
+
{ did: this.getOwnerDid(), privateKey: this.getOwnerSigningKey() },
|
|
126972
|
+
{ did: this.getRuntimeDid(), privateKey: this.getRuntimeSigningKey() }
|
|
126973
|
+
], PROVISION_BUSY_TIMEOUT_MS);
|
|
126974
|
+
upgraded > 0 && console.log(`[OwnerIdentity] Re-signed ${upgraded} attestation(s) as v2 in ${workspace.getFilePath()}`);
|
|
126975
|
+
} catch (err) {
|
|
126976
|
+
console.warn("[OwnerIdentity] Attestation v2 upgrade failed:", err);
|
|
126977
|
+
}
|
|
126978
|
+
}
|
|
126427
126979
|
/** Record that `ownerDid` is seed-derived (idempotent; no write when already set). */
|
|
126428
126980
|
markSeedDerived() {
|
|
126429
126981
|
this.settings.get(OWNER_SEED_DERIVED_KEY) !== !0 && this.settings.set(OWNER_SEED_DERIVED_KEY, !0);
|
|
@@ -126532,7 +127084,7 @@ var OwnerIdentityService = class {
|
|
|
126532
127084
|
let currentOwnerDid = this.getOwnerDid(), owner = deriveOwnerIdentity(normalized);
|
|
126533
127085
|
if (opts.expectedOwnerDid && owner.did !== opts.expectedOwnerDid)
|
|
126534
127086
|
throw new Error(`That phrase belongs to ${owner.did}, not this machine's owner ${opts.expectedOwnerDid}. Check the words, or use Import identity to switch owners.`);
|
|
126535
|
-
if (currentOwnerDid && currentOwnerDid !== owner.did) {
|
|
127087
|
+
if (this.assertSecretsWritable(), currentOwnerDid && currentOwnerDid !== owner.did) {
|
|
126536
127088
|
let legacy = this.settings.get("legacyOwnerDids") ?? [];
|
|
126537
127089
|
legacy.includes(currentOwnerDid) || this.settings.set("legacyOwnerDids", [...legacy, currentOwnerDid]);
|
|
126538
127090
|
}
|
|
@@ -126694,7 +127246,7 @@ var OwnerIdentityService = class {
|
|
|
126694
127246
|
}, signingRow = workspace.getIdentityRow("crypto:signing:private_key");
|
|
126695
127247
|
signingRow === null ? (workspace.generateIdentityKeys(null, opts.adoptKeys), keysGenerated = !0, stampAndAttest()) : signingRow.encryption_algo === "plain" && workspace.getDid() && !workspace.getMeta("adf_owner_did") && this.getOwnerSigningKey() && stampAndAttest();
|
|
126696
127248
|
let sealed = workspace.sealPlainRowsIntoEnvelopes();
|
|
126697
|
-
return { keysGenerated, sealed };
|
|
127249
|
+
return this.upgradeAttestations(workspace), { keysGenerated, sealed };
|
|
126698
127250
|
};
|
|
126699
127251
|
if (!(!workspace.hasEnvelopes() && this.getEnvelopeRecipients() !== null || workspace.getIdentityRow("crypto:signing:private_key") === null)) return provision();
|
|
126700
127252
|
try {
|
|
@@ -126986,7 +127538,7 @@ function normalizeDelegation(raw) {
|
|
|
126986
127538
|
if (!isNonEmptyString(d[field])) return null;
|
|
126987
127539
|
for (let field of ["expires_at", "scope"])
|
|
126988
127540
|
if (d[field] !== void 0 && typeof d[field] != "string") return null;
|
|
126989
|
-
return {
|
|
127541
|
+
return d.v === 2 ? d : {
|
|
126990
127542
|
issuer: d.issuer,
|
|
126991
127543
|
subject: d.subject,
|
|
126992
127544
|
role: d.role,
|
|
@@ -127813,22 +128365,45 @@ var TEST_KEYCHAIN_FILE_ENV = "ADF_TEST_KEYCHAIN_FILE", TestKeychainFileBackend =
|
|
|
127813
128365
|
function blockingSleep(ms) {
|
|
127814
128366
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
127815
128367
|
}
|
|
128368
|
+
var SecretStoreSelectionError = class extends Error {
|
|
128369
|
+
constructor(message) {
|
|
128370
|
+
super(message), this.name = "SecretStoreSelectionError";
|
|
128371
|
+
}
|
|
128372
|
+
}, STRICT_KEYCHAIN_REMEDY = `The daemon does not start, and it does not open the passphrase file ${SECRET_FILE_NAME}. Make the OS keychain usable and start the daemon again, or set ADF_SECRET_STORE=file (or unset it) to use the passphrase file.`;
|
|
127816
128373
|
function selectBackend(settingsPath2, deps = {}) {
|
|
127817
|
-
let forced = process.env.ADF_SECRET_STORE
|
|
128374
|
+
let forced = process.env.ADF_SECRET_STORE || void 0;
|
|
128375
|
+
if (forced !== void 0 && forced !== "file" && forced !== "keychain")
|
|
128376
|
+
throw new SecretStoreSelectionError('ADF_SECRET_STORE has an unsupported value. Set it to "keychain" or "file", or unset it to let the daemon choose.');
|
|
128377
|
+
let strict = forced === "keychain", file = () => new FileSecretBackend(join33(dirname17(settingsPath2), SECRET_FILE_NAME));
|
|
127818
128378
|
if (forced === "file") return { backend: file(), keychainError: null };
|
|
127819
|
-
|
|
128379
|
+
let keychainOff = process.env.ADF_KEYCHAIN;
|
|
128380
|
+
if (keychainOff === "0" || keychainOff === "off") {
|
|
128381
|
+
if (strict)
|
|
128382
|
+
throw new SecretStoreSelectionError(
|
|
128383
|
+
`ADF_SECRET_STORE=keychain conflicts with ADF_KEYCHAIN=${keychainOff}, which turns the OS keychain off. Unset ADF_KEYCHAIN to use the keychain, or set ADF_SECRET_STORE=file (or unset it) to use the passphrase file.`
|
|
128384
|
+
);
|
|
128385
|
+
return { backend: file(), keychainError: null };
|
|
128386
|
+
}
|
|
127820
128387
|
let fakePath = process.env[TEST_KEYCHAIN_FILE_ENV];
|
|
127821
|
-
if (fakePath)
|
|
127822
|
-
|
|
127823
|
-
|
|
128388
|
+
if (fakePath) {
|
|
128389
|
+
if (testSeamsAllowed())
|
|
128390
|
+
return console.warn(`[ADF Daemon] Test seam: ${fakePath} stands in for the OS keychain (ADF_TEST_SEAMS=1)`), { backend: new TestKeychainFileBackend(fakePath), keychainError: null };
|
|
128391
|
+
if (strict) throw new SecretStoreSelectionError(`ADF_SECRET_STORE=keychain, but ${TEST_KEYCHAIN_FILE_ENV} is set without the test seams (ADF_TEST_SEAMS=1 and an unpackaged build). ${STRICT_KEYCHAIN_REMEDY}`);
|
|
128392
|
+
return console.error(`[ADF Daemon] Ignoring ${TEST_KEYCHAIN_FILE_ENV}: test seams need ADF_TEST_SEAMS=1 and an unpackaged build. Using the passphrase file, not the OS keychain.`), { backend: file(), keychainError: null };
|
|
128393
|
+
}
|
|
128394
|
+
let probe = deps.probe ?? probeKeychain, sleep = deps.sleep ?? blockingSleep, platform3 = deps.platform ?? process.platform, result = probe(), tries = 1, expected = result.present && (platform3 === "win32" || platform3 === "darwin");
|
|
127824
128395
|
for (let i = 0; !result.backend && expected && i < KEYCHAIN_PROBE_DELAYS_MS.length; i++)
|
|
127825
|
-
console.warn(`[ADF Daemon] The OS keychain did not answer (${result.error ?? "unknown error"}); trying again in ${KEYCHAIN_PROBE_DELAYS_MS[i] / 1e3}s`), sleep(KEYCHAIN_PROBE_DELAYS_MS[i]), result = probe()
|
|
128396
|
+
console.warn(`[ADF Daemon] The OS keychain did not answer (${result.error ?? "unknown error"}); trying again in ${KEYCHAIN_PROBE_DELAYS_MS[i] / 1e3}s`), sleep(KEYCHAIN_PROBE_DELAYS_MS[i]), result = probe(), tries++;
|
|
127826
128397
|
if (result.backend) return { backend: result.backend, keychainError: null };
|
|
128398
|
+
if (strict) {
|
|
128399
|
+
let why = result.present ? `the OS keychain could not be read${tries > 1 ? ` after ${tries} tries` : ""} (${result.error ?? "unknown error"})` : "no OS keychain binding (@napi-rs/keyring) loads in this build";
|
|
128400
|
+
throw new SecretStoreSelectionError(`ADF_SECRET_STORE=keychain, but ${why}. ${STRICT_KEYCHAIN_REMEDY}`);
|
|
128401
|
+
}
|
|
127827
128402
|
if (expected) {
|
|
127828
128403
|
let error = result.error ?? "unknown error";
|
|
127829
128404
|
return console.error(`[ADF Daemon] The OS keychain could not be read after ${KEYCHAIN_PROBE_DELAYS_MS.length + 1} tries (${error}): using the passphrase file ${SECRET_FILE_NAME}. Owner create, restore and trust-daemon are refused until the daemon restarts with the keychain (adf daemon restart).`), { backend: file(), keychainError: error };
|
|
127830
128405
|
}
|
|
127831
|
-
return
|
|
128406
|
+
return { backend: file(), keychainError: null };
|
|
127832
128407
|
}
|
|
127833
128408
|
function readBootPassphrase(readFile3) {
|
|
127834
128409
|
if (process.env.ADF_OWNER_PASSPHRASE) return process.env.ADF_OWNER_PASSPHRASE;
|
|
@@ -128007,7 +128582,7 @@ var ProviderChecks = class {
|
|
|
128007
128582
|
cache = /* @__PURE__ */ new Map();
|
|
128008
128583
|
/** A check the host starts on its own: honours the opt-out (see file header). */
|
|
128009
128584
|
async autoCheck(cfg) {
|
|
128010
|
-
return this.opts.isEnabled()
|
|
128585
|
+
return !this.opts.isEnabled() && !isSubscriptionType(cfg.type) ? this.cache.get(providerTestCacheKey(cfg)) ?? "unchecked" : this.test(cfg);
|
|
128011
128586
|
}
|
|
128012
128587
|
async test(cfg, force = !1) {
|
|
128013
128588
|
let cacheKey = providerTestCacheKey(cfg);
|
|
@@ -128017,15 +128592,15 @@ var ProviderChecks = class {
|
|
|
128017
128592
|
let finish = (result) => (this.cache.set(cacheKey, result), result);
|
|
128018
128593
|
if (cfg.type === "chatgpt-subscription") {
|
|
128019
128594
|
let { getChatGptAuthManager: getChatGptAuthManager2 } = await import("./auth-manager-AJ32FZWS.mjs");
|
|
128020
|
-
return
|
|
128595
|
+
return getChatGptAuthManager2().isAuthenticated() ? "ok" : "unconfigured";
|
|
128021
128596
|
}
|
|
128022
128597
|
if (cfg.type === "grok-subscription") {
|
|
128023
128598
|
let { getGrokAuthManager: getGrokAuthManager2 } = await import("./auth-manager-C5OBEQK2.mjs");
|
|
128024
|
-
return
|
|
128599
|
+
return getGrokAuthManager2().isAuthenticated() ? "ok" : "unconfigured";
|
|
128025
128600
|
}
|
|
128026
128601
|
if (cfg.type === "claude-subscription") {
|
|
128027
128602
|
let { getClaudeAuthManager: getClaudeAuthManager2 } = await import("./auth-manager-TBNKCJ45.mjs");
|
|
128028
|
-
return
|
|
128603
|
+
return await getClaudeAuthManager2().isAuthenticated() ? "ok" : "unconfigured";
|
|
128029
128604
|
}
|
|
128030
128605
|
if (cfg.type === "anthropic") {
|
|
128031
128606
|
if (!cfg.apiKey) return finish("unconfigured");
|
|
@@ -128067,6 +128642,14 @@ var ProviderChecks = class {
|
|
|
128067
128642
|
import { constants as fsConstants3, createReadStream, createWriteStream as createWriteStream2, existsSync as existsSync19 } from "node:fs";
|
|
128068
128643
|
import { copyFile, link, lstat as lstat3, mkdir as mkdir2, mkdtemp as mkdtemp2, open as open2, readdir as readdir7, readFile as readFile2, realpath as realpath4, rename, rmdir, stat as stat5, unlink, writeFile as writeFile2 } from "node:fs/promises";
|
|
128069
128644
|
import { execFile as execFile11 } from "node:child_process";
|
|
128645
|
+
|
|
128646
|
+
// src/main/utils/agents-folder-name.ts
|
|
128647
|
+
function defaultAgentsFolderName(env = process.env) {
|
|
128648
|
+
let instance3 = env.ADF_INSTANCE?.trim().replace(/[^\w.-]/g, "_");
|
|
128649
|
+
return instance3 ? `adf-agents-${instance3}` : "adf-agents";
|
|
128650
|
+
}
|
|
128651
|
+
|
|
128652
|
+
// src/main/daemon/file-ops.ts
|
|
128070
128653
|
import { homedir as homedir5, tmpdir as tmpdir8 } from "node:os";
|
|
128071
128654
|
import { basename as basename14, delimiter as delimiter2, dirname as dirname19, isAbsolute as isAbsolute6, join as join36, resolve as resolve15 } from "node:path";
|
|
128072
128655
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
@@ -129612,10 +130195,10 @@ async function findDocumentsDir() {
|
|
|
129612
130195
|
return fallback;
|
|
129613
130196
|
}
|
|
129614
130197
|
async function resolveAgentsFolder(settings2) {
|
|
129615
|
-
return configuredAgentsFolder(settings2) ?? { path: join36(await documentsDir(),
|
|
130198
|
+
return configuredAgentsFolder(settings2) ?? { path: join36(await documentsDir(), defaultAgentsFolderName()), source: "default" };
|
|
129616
130199
|
}
|
|
129617
130200
|
function resolveAgentsFolderSync(settings2) {
|
|
129618
|
-
return configuredAgentsFolder(settings2) ?? { path: join36(documentsDirSync(),
|
|
130201
|
+
return configuredAgentsFolder(settings2) ?? { path: join36(documentsDirSync(), defaultAgentsFolderName()), source: "default" };
|
|
129619
130202
|
}
|
|
129620
130203
|
function configuredAgentsFolder(settings2) {
|
|
129621
130204
|
let configured = settings2?.get("agentsFolder");
|
|
@@ -133478,6 +134061,14 @@ function registerFleetRoutes(server, ctx) {
|
|
|
133478
134061
|
let success = await manager.restart(type);
|
|
133479
134062
|
return { success, error: success ? void 0 : `Could not restart the ${type} channel.` };
|
|
133480
134063
|
}), server.get("/network/peers/health", async (request) => probePeerHealth(request.query.url)), server.get("/network/peers/shared-file", async (request) => fetchPeerSharedFile(request.query.baseUrl, request.query.path)), server.post("/runtime/emergency-stop", async () => {
|
|
134064
|
+
let releaseKill = RuntimeGate.beginKill();
|
|
134065
|
+
try {
|
|
134066
|
+
return await emergencyStop();
|
|
134067
|
+
} finally {
|
|
134068
|
+
releaseKill();
|
|
134069
|
+
}
|
|
134070
|
+
});
|
|
134071
|
+
let emergencyStop = async () => {
|
|
133481
134072
|
console.log("[EmergencyStop] Shutting down everything...");
|
|
133482
134073
|
let deps = gapDeps(ctx), skipped = [], failed = [], step = async (name15, run2) => {
|
|
133483
134074
|
try {
|
|
@@ -133486,12 +134077,21 @@ function registerFleetRoutes(server, ctx) {
|
|
|
133486
134077
|
failed.push(name15), console.error(`[EmergencyStop] ${name15} error:`, e);
|
|
133487
134078
|
}
|
|
133488
134079
|
};
|
|
133489
|
-
|
|
134080
|
+
await step("mesh", () => {
|
|
133490
134081
|
mesh?.isEnabled() && (mesh.disableMesh ? mesh.disableMesh() : skipped.push("mesh"));
|
|
133491
134082
|
});
|
|
133492
|
-
let
|
|
133493
|
-
|
|
133494
|
-
|
|
134083
|
+
let listedAgents = 0;
|
|
134084
|
+
for (let pass = 0; pass < 2; pass++) {
|
|
134085
|
+
if (pass > 0) {
|
|
134086
|
+
let loading = await runtime2.settleLoads();
|
|
134087
|
+
loading.length > 0 && failed.push(...loading.map((filePath) => `still loading: ${filePath}`));
|
|
134088
|
+
}
|
|
134089
|
+
let agents = runtime2.listAgents();
|
|
134090
|
+
listedAgents += agents.length, await Promise.all(agents.map((agent) => step(`agent ${agent.id}`, () => runtime2.unloadAgent(agent.id, { mode: "immediate" }))));
|
|
134091
|
+
}
|
|
134092
|
+
let left = runtime2.listAgents();
|
|
134093
|
+
left.length > 0 && failed.push(...left.map((agent) => `still loaded: ${agent.id}`));
|
|
134094
|
+
let stoppedAgents = listedAgents - failed.filter((name15) => name15.startsWith("agent ")).length;
|
|
133495
134095
|
if (await step("ws connections", () => options.wsService?.stopAll?.()), await step("mesh server", async () => {
|
|
133496
134096
|
deps.meshServer ? await deps.meshServer.stop() : skipped.push("mesh server");
|
|
133497
134097
|
}), await step("child processes", () => killAllTracked()), await step("host execs", () => killAllHostExecs()), await step("sandbox workers", () => {
|
|
@@ -133512,7 +134112,7 @@ function registerFleetRoutes(server, ctx) {
|
|
|
133512
134112
|
...skipped.length ? { skipped } : {},
|
|
133513
134113
|
...failed.length ? { failed } : {}
|
|
133514
134114
|
};
|
|
133515
|
-
}
|
|
134115
|
+
};
|
|
133516
134116
|
}
|
|
133517
134117
|
|
|
133518
134118
|
// src/main/daemon/routes/dashboard-routes.ts
|
|
@@ -134181,7 +134781,7 @@ function registerRegistryRoutes(server, ctx) {
|
|
|
134181
134781
|
}), server.post("/registry/agents/:id/bring-home", async (request) => {
|
|
134182
134782
|
let id = request.params.id, factory12 = ctx.options.agentFactory, result = await bringRegistryAgentHome(() => agentRegistry().resolveFile(id), {
|
|
134183
134783
|
agentsFolder: () => {
|
|
134184
|
-
let configured = settings2?.get("agentsFolder"), folder = factory12?.defaultDirectory() ?? (typeof configured == "string" && configured.trim() ? resolve17(configured.trim()) : join43(homedir7(), "Documents",
|
|
134784
|
+
let configured = settings2?.get("agentsFolder"), folder = factory12?.defaultDirectory() ?? (typeof configured == "string" && configured.trim() ? resolve17(configured.trim()) : join43(homedir7(), "Documents", defaultAgentsFolderName()));
|
|
134185
134785
|
return mkdirSync17(folder, { recursive: !0 }), folder;
|
|
134186
134786
|
},
|
|
134187
134787
|
providers: settings2?.get("providers") ?? [],
|
|
@@ -137641,12 +138241,10 @@ var BASE_REVISION_INVALID = "baseRevision (or If-Match) must be a revision numbe
|
|
|
137641
138241
|
function getOpenApiSpec() {
|
|
137642
138242
|
return openapi_default;
|
|
137643
138243
|
}
|
|
137644
|
-
var SETTINGS_SECRET_KEYS = ["ownerMnemonic", "runtimePrivateKey", "runtimeEncPrivateKey", "mcpOauthCredentials"], SUPERSEDED_MNEMONIC_PREFIX = "ownerMnemonicSuperseded:";
|
|
137645
|
-
function isSecretSettingsKey(key) {
|
|
137646
|
-
return SETTINGS_SECRET_KEYS.includes(key) || key.startsWith(SUPERSEDED_MNEMONIC_PREFIX);
|
|
137647
|
-
}
|
|
137648
138244
|
var SETTINGS_WRITE_DENY_KEYS = [
|
|
137649
138245
|
...SETTINGS_SECRET_KEYS,
|
|
138246
|
+
// How Studio stores those secrets: the user's own choice in Studio, never set over HTTP.
|
|
138247
|
+
SECRET_STORAGE_POLICY_KEY,
|
|
137650
138248
|
"trustedDaemonEncKeys",
|
|
137651
138249
|
// Owner/runtime identity: changed only through /identity (daemon) or Studio.
|
|
137652
138250
|
"ownerDid",
|
|
@@ -138818,13 +139416,13 @@ function createDaemonHttpApi(runtime2, opts = {}) {
|
|
|
138818
139416
|
}
|
|
138819
139417
|
}), server.post("/agents/:id/start", async (request, reply) => {
|
|
138820
139418
|
try {
|
|
138821
|
-
let preflight = request.query?.preflight === "1" || request.query?.preflight === "true", hasUserMessage = request.query?.hasUserMessage === "1" || request.query?.hasUserMessage === "true", credentialsLocked;
|
|
139419
|
+
let killEpoch = RuntimeGate.killEpoch, preflight = request.query?.preflight === "1" || request.query?.preflight === "true", hasUserMessage = request.query?.hasUserMessage === "1" || request.query?.hasUserMessage === "true", credentialsLocked;
|
|
138822
139420
|
if (preflight && !runtime2.getAgent(request.params.id)) {
|
|
138823
139421
|
let check = await runtime2.preflightProvider(request.params.id);
|
|
138824
139422
|
if (!check.ok) return reply.code(409).send({ error: check.error, code: check.code ?? "provider_check_failed" });
|
|
138825
139423
|
credentialsLocked = check.credentialsLocked;
|
|
138826
139424
|
}
|
|
138827
|
-
let result = await runtime2.startOrLoadAgent(request.params.id, { hasUserMessage });
|
|
139425
|
+
let result = await runtime2.startOrLoadAgent(request.params.id, { hasUserMessage, killEpoch });
|
|
138828
139426
|
return {
|
|
138829
139427
|
success: !0,
|
|
138830
139428
|
loaded: result.loaded,
|
|
@@ -138867,6 +139465,18 @@ function createDaemonHttpApi(runtime2, opts = {}) {
|
|
|
138867
139465
|
} catch (err) {
|
|
138868
139466
|
return handleRuntimeError(reply, err);
|
|
138869
139467
|
}
|
|
139468
|
+
}), server.post("/agents/:id/commands/:name/run", async (request, reply) => {
|
|
139469
|
+
let { id, name: name15 } = request.params;
|
|
139470
|
+
if (!runtime2.getAgentOrDocument(id)) return notFound3(reply, `Unknown agent "${id}"`);
|
|
139471
|
+
if (!runtime2.getAgent(id)) return notRunning(reply, id);
|
|
139472
|
+
let body = request.body;
|
|
139473
|
+
if (body !== void 0 && (!isRecord4(body) || body.args !== void 0 && typeof body.args != "string" || body.loop !== void 0 && typeof body.loop != "string" || body.authorize !== void 0 && typeof body.authorize != "boolean" || body.requestId !== void 0 && typeof body.requestId != "string"))
|
|
139474
|
+
return reply.code(400).send({ error: "Command body must contain string args, loop and requestId, and a boolean authorize.", code: "invalid_request" });
|
|
139475
|
+
try {
|
|
139476
|
+
return await runtime2.runAgentCommand(id, name15, body ?? {});
|
|
139477
|
+
} catch (err) {
|
|
139478
|
+
return handleRuntimeError(reply, err);
|
|
139479
|
+
}
|
|
138870
139480
|
}), server.post("/agents/:id/compact", async (request, reply) => {
|
|
138871
139481
|
if (!runtime2.getAgentOrDocument(request.params.id)) return notFound3(reply, `Unknown agent "${request.params.id}"`);
|
|
138872
139482
|
try {
|
|
@@ -139117,7 +139727,7 @@ async function listProviderModels(runtime2, settingsStore, providerId, agentId,
|
|
|
139117
139727
|
return { provider: providerId, models: await listGrokSubscriptionModels(getGrokAuthManager()) };
|
|
139118
139728
|
}
|
|
139119
139729
|
if (cfg.type === "claude-subscription") {
|
|
139120
|
-
let { listClaudeSubscriptionModels } = await import("./claude-subscription-
|
|
139730
|
+
let { listClaudeSubscriptionModels } = await import("./claude-subscription-EB4LAAVV.mjs");
|
|
139121
139731
|
return { provider: providerId, models: await listClaudeSubscriptionModels() };
|
|
139122
139732
|
}
|
|
139123
139733
|
if (cfg.type === "anthropic") {
|
|
@@ -140088,6 +140698,8 @@ var CLIENT_SETTINGS_KEYS = [
|
|
|
140088
140698
|
// Owner and runtime identity (§5). Key material never crosses HTTP
|
|
140089
140699
|
// (SETTINGS_SECRET_KEYS, SETTINGS_WRITE_DENY_KEYS in daemon/http-api.ts).
|
|
140090
140700
|
"ownerMnemonic",
|
|
140701
|
+
// How Studio stores the secrets above (src/main/services/secret-storage-policy.ts).
|
|
140702
|
+
"secretStoragePolicy",
|
|
140091
140703
|
"ownerDid",
|
|
140092
140704
|
"ownerDidSeedDerived",
|
|
140093
140705
|
"ownerEncPublicKey",
|
|
@@ -141039,7 +141651,7 @@ process.on("uncaughtException", (err) => {
|
|
|
141039
141651
|
process.on("unhandledRejection", (reason) => {
|
|
141040
141652
|
console.error("[ADF Daemon] Unhandled rejection:", reason instanceof Error ? reason.stack : reason);
|
|
141041
141653
|
});
|
|
141042
|
-
var port = Number(process.env.ADF_DAEMON_PORT ?? 7385), host = process.env.ADF_DAEMON_HOST ?? "127.0.0.1", pidFile = process.env.ADF_DAEMON_PIDFILE, settingsPath = process.env.ADF_DAEMON_SETTINGS ?? defaultSettingsPath(), daemonVersion = "0.8.
|
|
141654
|
+
var port = Number(process.env.ADF_DAEMON_PORT ?? 7385), host = process.env.ADF_DAEMON_HOST ?? "127.0.0.1", pidFile = process.env.ADF_DAEMON_PIDFILE, settingsPath = process.env.ADF_DAEMON_SETTINGS ?? defaultSettingsPath(), daemonVersion = "0.8.1", startedBy = takeLaunchEnv();
|
|
141043
141655
|
console.log(`[ADF Daemon] Version ${daemonVersion} (pid ${process.pid}, started by ${startedBy})`);
|
|
141044
141656
|
var settings = new FileSettingsStore(settingsPath);
|
|
141045
141657
|
processAgentLeases().configure({ kind: "daemon", settingsPath, version: daemonVersion });
|
|
@@ -141068,12 +141680,18 @@ if (behindProxy) {
|
|
|
141068
141680
|
} catch (err) {
|
|
141069
141681
|
noteLocalProofProblem(`the local proof file could not be written or protected: ${err instanceof Error ? err.message : String(err)}`), console.error("[ADF Daemon] Could not write or protect the local proof file; owner import (adf identity import) and the stored-value reveal routes stay unavailable:", err instanceof Error ? err.message : err);
|
|
141070
141682
|
}
|
|
141071
|
-
var ownerIdentity
|
|
141072
|
-
|
|
141073
|
-
|
|
141074
|
-
|
|
141075
|
-
|
|
141076
|
-
|
|
141683
|
+
var ownerIdentity;
|
|
141684
|
+
try {
|
|
141685
|
+
ownerIdentity = new DaemonIdentity({
|
|
141686
|
+
settings,
|
|
141687
|
+
settingsPath,
|
|
141688
|
+
encKey: daemonEncKey,
|
|
141689
|
+
bootPassphrase: readBootPassphrase((path) => readFileSync14(path, "utf-8"))
|
|
141690
|
+
});
|
|
141691
|
+
} catch (err) {
|
|
141692
|
+
if (!(err instanceof SecretStoreSelectionError)) throw err;
|
|
141693
|
+
console.error(`[ADF Daemon] Owner secret store: ${err.message}`), process.exit(1);
|
|
141694
|
+
}
|
|
141077
141695
|
settings.setProviderKeyVault(ownerIdentity.providerKeys);
|
|
141078
141696
|
{
|
|
141079
141697
|
let initial = ownerIdentity.refresh();
|