@wrongstack/core 0.6.0 → 0.6.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/{agent-bridge-BKNiE1VH.d.ts → agent-bridge-DaCvA_uK.d.ts} +1 -1
- package/dist/coordination/index.d.ts +5 -5
- package/dist/coordination/index.js +178 -54
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +10 -10
- package/dist/defaults/index.js +534 -75
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-DPQKFX7W.d.ts → events-CzkeaVVl.d.ts} +8 -2
- package/dist/execution/index.d.ts +149 -6
- package/dist/execution/index.js +345 -16
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +2 -2
- package/dist/{goal-store-BQ3YX1h1.d.ts → goal-store-DVCfj7Ff.d.ts} +20 -0
- package/dist/{index-B0qTujQW.d.ts → index-BkKLQjea.d.ts} +1 -1
- package/dist/{index-DkdRz6yK.d.ts → index-i9rPR53g.d.ts} +11 -4
- package/dist/index.d.ts +50 -16
- package/dist/index.js +769 -86
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +2 -2
- package/dist/kernel/index.d.ts +2 -2
- package/dist/kernel/index.js.map +1 -1
- package/dist/{multi-agent-Cpp7FXUl.d.ts → multi-agent-MfI6dmv-.d.ts} +30 -5
- package/dist/observability/index.d.ts +1 -1
- package/dist/{path-resolver--g_hKJ7V.d.ts → path-resolver-CWINz5XR.d.ts} +1 -1
- package/dist/{plan-templates-CKJs_sYh.d.ts → plan-templates-Bne1pB4d.d.ts} +1 -1
- package/dist/{provider-runner-hl4Il3xS.d.ts → provider-runner-CZYIzeBp.d.ts} +1 -1
- package/dist/sdd/index.d.ts +2 -2
- package/dist/storage/index.d.ts +3 -3
- package/dist/storage/index.js +3 -0
- package/dist/storage/index.js.map +1 -1
- package/dist/{tool-executor-B03CRwu-.d.ts → tool-executor-40Q6shR-.d.ts} +1 -1
- package/dist/types/index.d.ts +7 -7
- package/dist/types/index.js +16 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -2934,13 +2934,17 @@ var ToolExecutor = class {
|
|
|
2934
2934
|
const ctrl = new AbortController();
|
|
2935
2935
|
const timer = setTimeout(() => ctrl.abort(new Error("tool timeout")), timeoutMs);
|
|
2936
2936
|
const combined = AbortSignal.any([parentSignal, ctrl.signal]);
|
|
2937
|
+
let cleanupCalled = false;
|
|
2938
|
+
let caught = false;
|
|
2937
2939
|
try {
|
|
2938
2940
|
if (typeof tool.executeStream === "function") {
|
|
2939
2941
|
return await this.runStreamedTool(tool, input, ctx, combined, toolUseId);
|
|
2940
2942
|
}
|
|
2941
2943
|
return await tool.execute(input, ctx, { signal: combined });
|
|
2942
2944
|
} catch (err) {
|
|
2945
|
+
caught = true;
|
|
2943
2946
|
if (combined.aborted && typeof tool.cleanup === "function") {
|
|
2947
|
+
cleanupCalled = true;
|
|
2944
2948
|
try {
|
|
2945
2949
|
await tool.cleanup(input, ctx);
|
|
2946
2950
|
} catch {
|
|
@@ -2949,6 +2953,16 @@ var ToolExecutor = class {
|
|
|
2949
2953
|
throw err;
|
|
2950
2954
|
} finally {
|
|
2951
2955
|
clearTimeout(timer);
|
|
2956
|
+
if (combined.aborted && !caught) {
|
|
2957
|
+
if (!cleanupCalled && typeof tool.cleanup === "function") {
|
|
2958
|
+
try {
|
|
2959
|
+
await tool.cleanup(input, ctx);
|
|
2960
|
+
} catch {
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
const reason = combined.reason instanceof Error ? combined.reason : new Error(typeof combined.reason === "string" ? combined.reason : "aborted");
|
|
2964
|
+
throw reason;
|
|
2965
|
+
}
|
|
2952
2966
|
}
|
|
2953
2967
|
}
|
|
2954
2968
|
async runStreamedTool(tool, input, ctx, signal, toolUseId) {
|
|
@@ -3006,7 +3020,8 @@ var ToolExecutor = class {
|
|
|
3006
3020
|
if (subjectKey) {
|
|
3007
3021
|
const v = obj[subjectKey];
|
|
3008
3022
|
if (typeof v === "string") {
|
|
3009
|
-
|
|
3023
|
+
const isPathKey = subjectKey === "path" || subjectKey === "file" || subjectKey === "files";
|
|
3024
|
+
return isPathKey ? normalizePath(v) : escapeGlob(v);
|
|
3010
3025
|
}
|
|
3011
3026
|
}
|
|
3012
3027
|
if (toolName === "bash" && typeof obj.command === "string") {
|
|
@@ -6277,17 +6292,23 @@ async function streamProviderToResponse(provider, req, signal, ctx, events) {
|
|
|
6277
6292
|
handleTextDelta(state, ev.text);
|
|
6278
6293
|
events.emit("provider.text_delta", { ctx, text: ev.text });
|
|
6279
6294
|
break;
|
|
6280
|
-
case "tool_use_start":
|
|
6281
|
-
|
|
6282
|
-
|
|
6295
|
+
case "tool_use_start": {
|
|
6296
|
+
const idVal = ev.id;
|
|
6297
|
+
const nameVal = ev.name;
|
|
6298
|
+
handleToolUseStart(state, { id: idVal, name: nameVal });
|
|
6299
|
+
const emittedPayload = { ctx, id: idVal ?? "unknown", name: nameVal ?? "unknown" };
|
|
6300
|
+
events.emit("provider.tool_use_start", emittedPayload);
|
|
6283
6301
|
break;
|
|
6302
|
+
}
|
|
6284
6303
|
case "tool_use_input_delta":
|
|
6285
6304
|
handleToolUseInputDelta(state, ev);
|
|
6286
6305
|
break;
|
|
6287
|
-
case "tool_use_stop":
|
|
6306
|
+
case "tool_use_stop": {
|
|
6307
|
+
const stoppedName = state.tools.get(ev.id)?.name ?? "unknown";
|
|
6288
6308
|
handleToolUseStop(state, ev);
|
|
6289
|
-
events.emit("provider.tool_use_stop", { ctx, id: ev.id });
|
|
6309
|
+
events.emit("provider.tool_use_stop", { ctx, id: ev.id, name: stoppedName });
|
|
6290
6310
|
break;
|
|
6311
|
+
}
|
|
6291
6312
|
case "thinking_start":
|
|
6292
6313
|
handleThinkingStart(state, ev);
|
|
6293
6314
|
break;
|
|
@@ -7303,6 +7324,8 @@ function emptyGoal(goal) {
|
|
|
7303
7324
|
lastActivityAt: now,
|
|
7304
7325
|
iterations: 0,
|
|
7305
7326
|
engineState: "idle",
|
|
7327
|
+
goalState: "active",
|
|
7328
|
+
todoAttempts: {},
|
|
7306
7329
|
journal: []
|
|
7307
7330
|
};
|
|
7308
7331
|
}
|
|
@@ -7340,6 +7363,7 @@ function formatGoal(goal, journalLimit = 10) {
|
|
|
7340
7363
|
lines.push(`Set: ${goal.setAt}`);
|
|
7341
7364
|
lines.push(`Last activity: ${goal.lastActivityAt}`);
|
|
7342
7365
|
lines.push(`Iterations: ${goal.iterations}`);
|
|
7366
|
+
lines.push(`Mission: ${goal.goalState ?? "active"}`);
|
|
7343
7367
|
lines.push(`Engine: ${goal.engineState}`);
|
|
7344
7368
|
const usage = summarizeUsage(goal);
|
|
7345
7369
|
if (usage.iterationsWithUsage > 0) {
|
|
@@ -7363,6 +7387,8 @@ function formatGoal(goal, journalLimit = 10) {
|
|
|
7363
7387
|
|
|
7364
7388
|
// src/execution/eternal-autonomy.ts
|
|
7365
7389
|
var execFileP = promisify(execFile);
|
|
7390
|
+
var BRAINSTORM_DONE = /* @__PURE__ */ Symbol("brainstorm-done");
|
|
7391
|
+
var GOAL_COMPLETE_MARKER = /^\s*\[goal[_\s-]?complete\]\s*$/im;
|
|
7366
7392
|
var EternalAutonomyEngine = class {
|
|
7367
7393
|
constructor(opts) {
|
|
7368
7394
|
this.opts = opts;
|
|
@@ -7372,6 +7398,14 @@ var EternalAutonomyEngine = class {
|
|
|
7372
7398
|
state = "idle";
|
|
7373
7399
|
stopRequested = false;
|
|
7374
7400
|
consecutiveFailures = 0;
|
|
7401
|
+
consecutiveBrainstormDone = 0;
|
|
7402
|
+
/**
|
|
7403
|
+
* Count of consecutive transient (recoverable) provider failures. Drives
|
|
7404
|
+
* the exponential backoff between iterations. Reset on the first
|
|
7405
|
+
* successful iteration so a single bad afternoon doesn't permanently
|
|
7406
|
+
* slow the loop down.
|
|
7407
|
+
*/
|
|
7408
|
+
consecutiveTransientRetries = 0;
|
|
7375
7409
|
currentCtrl = null;
|
|
7376
7410
|
iterationsSinceCompact = 0;
|
|
7377
7411
|
goalPath;
|
|
@@ -7441,9 +7475,16 @@ var EternalAutonomyEngine = class {
|
|
|
7441
7475
|
this.stopRequested = true;
|
|
7442
7476
|
return false;
|
|
7443
7477
|
}
|
|
7478
|
+
const missionState = goal.goalState ?? "active";
|
|
7479
|
+
if (missionState !== "active") {
|
|
7480
|
+
this.stopRequested = true;
|
|
7481
|
+
return false;
|
|
7482
|
+
}
|
|
7444
7483
|
const action = await this.decide(goal);
|
|
7445
7484
|
if (!action) {
|
|
7446
|
-
|
|
7485
|
+
if (!this.stopRequested) {
|
|
7486
|
+
await sleep(5e3);
|
|
7487
|
+
}
|
|
7447
7488
|
return false;
|
|
7448
7489
|
}
|
|
7449
7490
|
const ctrl = new AbortController();
|
|
@@ -7454,13 +7495,29 @@ var EternalAutonomyEngine = class {
|
|
|
7454
7495
|
);
|
|
7455
7496
|
let status = "success";
|
|
7456
7497
|
let note;
|
|
7498
|
+
let finalText = "";
|
|
7499
|
+
let isTransientFailure = false;
|
|
7457
7500
|
const tc = this.opts.agent.ctx?.tokenCounter;
|
|
7458
7501
|
const beforeUsage = tc?.total?.();
|
|
7459
7502
|
const beforeCost = tc?.estimateCost?.().total;
|
|
7460
7503
|
try {
|
|
7461
7504
|
const result = await this.opts.agent.run(
|
|
7462
7505
|
[{ type: "text", text: action.directive }],
|
|
7463
|
-
{
|
|
7506
|
+
{
|
|
7507
|
+
signal: ctrl.signal,
|
|
7508
|
+
// Enable per-call autonomous continuation so the agent can chain
|
|
7509
|
+
// multiple internal tool/response cycles end-to-end on one
|
|
7510
|
+
// directive instead of returning to the engine after a single
|
|
7511
|
+
// round-trip. The model uses `[continue]` / `[done]` markers
|
|
7512
|
+
// (or the `continue_to_next_iteration` tool) to control the
|
|
7513
|
+
// inner loop. Without this flag the engine produced shallow
|
|
7514
|
+
// iterations and almost never let a real task finish.
|
|
7515
|
+
autonomousContinue: true,
|
|
7516
|
+
// Cap the inner loop so a runaway agent.run can't burn through
|
|
7517
|
+
// the iteration timeout — the engine's own outer loop is the
|
|
7518
|
+
// long-running thing, each tick should be bounded.
|
|
7519
|
+
maxIterations: this.opts.iterationMaxAgentSteps ?? 50
|
|
7520
|
+
}
|
|
7464
7521
|
);
|
|
7465
7522
|
if (result.status === "aborted") {
|
|
7466
7523
|
status = "aborted";
|
|
@@ -7468,22 +7525,30 @@ var EternalAutonomyEngine = class {
|
|
|
7468
7525
|
} else if (result.status === "failed") {
|
|
7469
7526
|
status = "failure";
|
|
7470
7527
|
note = result.error?.describe?.() ?? "agent run failed";
|
|
7528
|
+
isTransientFailure = result.error?.recoverable === true;
|
|
7471
7529
|
} else if (result.status === "max_iterations") {
|
|
7472
7530
|
status = "failure";
|
|
7473
7531
|
note = `max iterations (${result.iterations})`;
|
|
7474
7532
|
} else {
|
|
7475
7533
|
status = "success";
|
|
7476
|
-
|
|
7534
|
+
finalText = result.finalText ?? "";
|
|
7535
|
+
const tail = finalText.slice(0, 240).replace(/\s+/g, " ").trim();
|
|
7477
7536
|
if (tail) note = tail;
|
|
7478
7537
|
}
|
|
7479
7538
|
} catch (err) {
|
|
7480
7539
|
const isAbort = err instanceof Error && (err.name === "AbortError" || err.message.includes("abort"));
|
|
7481
7540
|
status = isAbort ? "aborted" : "failure";
|
|
7482
7541
|
note = err instanceof Error ? err.message : String(err);
|
|
7542
|
+
if (!isAbort && typeof err?.recoverable === "boolean") {
|
|
7543
|
+
isTransientFailure = err.recoverable;
|
|
7544
|
+
}
|
|
7483
7545
|
} finally {
|
|
7484
7546
|
clearTimeout(timer);
|
|
7485
7547
|
this.currentCtrl = null;
|
|
7486
7548
|
}
|
|
7549
|
+
if (action.source === "todo" && action.todoId && status !== "success") {
|
|
7550
|
+
await this.bumpTodoAttempt(action.todoId);
|
|
7551
|
+
}
|
|
7487
7552
|
const afterUsage = tc?.total?.();
|
|
7488
7553
|
const afterCost = tc?.estimateCost?.().total;
|
|
7489
7554
|
const tokens = beforeUsage && afterUsage ? {
|
|
@@ -7516,6 +7581,14 @@ var EternalAutonomyEngine = class {
|
|
|
7516
7581
|
costUsd
|
|
7517
7582
|
});
|
|
7518
7583
|
if (status === "failure") {
|
|
7584
|
+
if (isTransientFailure) {
|
|
7585
|
+
this.consecutiveTransientRetries++;
|
|
7586
|
+
const delay = this.computeTransientBackoffMs();
|
|
7587
|
+
if (delay > 0) {
|
|
7588
|
+
await this.sleepInterruptible(delay);
|
|
7589
|
+
}
|
|
7590
|
+
return false;
|
|
7591
|
+
}
|
|
7519
7592
|
this.consecutiveFailures++;
|
|
7520
7593
|
return false;
|
|
7521
7594
|
}
|
|
@@ -7524,6 +7597,12 @@ var EternalAutonomyEngine = class {
|
|
|
7524
7597
|
this.consecutiveFailures++;
|
|
7525
7598
|
return false;
|
|
7526
7599
|
}
|
|
7600
|
+
this.consecutiveTransientRetries = 0;
|
|
7601
|
+
if (GOAL_COMPLETE_MARKER.test(finalText)) {
|
|
7602
|
+
await this.markGoalCompleted(action, finalText);
|
|
7603
|
+
this.stopRequested = true;
|
|
7604
|
+
return true;
|
|
7605
|
+
}
|
|
7527
7606
|
this.iterationsSinceCompact++;
|
|
7528
7607
|
await this.maybeCompact().catch((err) => {
|
|
7529
7608
|
this.opts.onError?.(
|
|
@@ -7587,11 +7666,12 @@ var EternalAutonomyEngine = class {
|
|
|
7587
7666
|
async decide(goal) {
|
|
7588
7667
|
const forceBrainstorm = this.consecutiveFailures >= (this.opts.failureBudget ?? 3);
|
|
7589
7668
|
if (!forceBrainstorm) {
|
|
7590
|
-
const todo = this.pickPendingTodo();
|
|
7669
|
+
const todo = this.pickPendingTodo(goal);
|
|
7591
7670
|
if (todo) {
|
|
7592
7671
|
return {
|
|
7593
7672
|
source: "todo",
|
|
7594
7673
|
task: todo.content,
|
|
7674
|
+
todoId: todo.id,
|
|
7595
7675
|
directive: this.buildDirective(goal, "todo", todo.content)
|
|
7596
7676
|
};
|
|
7597
7677
|
}
|
|
@@ -7605,17 +7685,38 @@ var EternalAutonomyEngine = class {
|
|
|
7605
7685
|
}
|
|
7606
7686
|
}
|
|
7607
7687
|
const brainstormed = await this.brainstormTask(goal);
|
|
7688
|
+
if (brainstormed === BRAINSTORM_DONE) {
|
|
7689
|
+
this.consecutiveBrainstormDone++;
|
|
7690
|
+
const threshold = this.opts.brainstormDoneStopThreshold ?? 3;
|
|
7691
|
+
if (this.consecutiveBrainstormDone >= threshold) {
|
|
7692
|
+
await this.markGoalCompleted(
|
|
7693
|
+
{ source: "brainstorm", task: "no further work", directive: "" },
|
|
7694
|
+
`brainstorm returned DONE ${this.consecutiveBrainstormDone}x in a row`
|
|
7695
|
+
);
|
|
7696
|
+
this.stopRequested = true;
|
|
7697
|
+
}
|
|
7698
|
+
return null;
|
|
7699
|
+
}
|
|
7608
7700
|
if (!brainstormed) return null;
|
|
7701
|
+
this.consecutiveBrainstormDone = 0;
|
|
7609
7702
|
return {
|
|
7610
7703
|
source: "brainstorm",
|
|
7611
7704
|
task: brainstormed,
|
|
7612
7705
|
directive: this.buildDirective(goal, "brainstorm", brainstormed)
|
|
7613
7706
|
};
|
|
7614
7707
|
}
|
|
7615
|
-
pickPendingTodo() {
|
|
7708
|
+
pickPendingTodo(goal) {
|
|
7616
7709
|
const todos = this.opts.agent.ctx.todos;
|
|
7617
7710
|
if (!Array.isArray(todos)) return null;
|
|
7618
|
-
|
|
7711
|
+
const attempts = goal.todoAttempts ?? {};
|
|
7712
|
+
const ceiling = this.opts.todoMaxAttempts ?? 3;
|
|
7713
|
+
for (const t2 of todos) {
|
|
7714
|
+
if (t2.status !== "pending") continue;
|
|
7715
|
+
const used = attempts[t2.id] ?? 0;
|
|
7716
|
+
if (used >= ceiling) continue;
|
|
7717
|
+
return t2;
|
|
7718
|
+
}
|
|
7719
|
+
return null;
|
|
7619
7720
|
}
|
|
7620
7721
|
async pickGitTask() {
|
|
7621
7722
|
let out;
|
|
@@ -7652,7 +7753,10 @@ ${lastFew}` : "No prior iterations yet.",
|
|
|
7652
7753
|
"- One sentence, imperative form, under 200 chars.",
|
|
7653
7754
|
"- No preamble, no explanation, no markdown \u2014 just the task line.",
|
|
7654
7755
|
"- If recent iterations show repeated failures on the same target, pivot.",
|
|
7655
|
-
"- If the goal appears fully accomplished
|
|
7756
|
+
"- If the goal appears fully accomplished AND you can name a concrete",
|
|
7757
|
+
" artifact / test / output that proves it, output exactly: DONE",
|
|
7758
|
+
"- Be conservative with DONE: if the recent journal contains failures",
|
|
7759
|
+
" or aborted entries, the goal is almost certainly NOT done."
|
|
7656
7760
|
].join("\n");
|
|
7657
7761
|
try {
|
|
7658
7762
|
const ctrl = new AbortController();
|
|
@@ -7664,9 +7768,11 @@ ${lastFew}` : "No prior iterations yet.",
|
|
|
7664
7768
|
);
|
|
7665
7769
|
if (result.status !== "done") return null;
|
|
7666
7770
|
const text = (result.finalText ?? "").trim();
|
|
7667
|
-
if (!text
|
|
7771
|
+
if (!text) return null;
|
|
7772
|
+
if (/^DONE\.?$/i.test(text)) return BRAINSTORM_DONE;
|
|
7668
7773
|
const firstLine = text.split("\n").find((l) => l.trim().length > 0)?.trim();
|
|
7669
7774
|
if (!firstLine) return null;
|
|
7775
|
+
if (/^DONE\.?$/i.test(firstLine)) return BRAINSTORM_DONE;
|
|
7670
7776
|
return firstLine.slice(0, 240);
|
|
7671
7777
|
} finally {
|
|
7672
7778
|
clearTimeout(timer);
|
|
@@ -7676,19 +7782,82 @@ ${lastFew}` : "No prior iterations yet.",
|
|
|
7676
7782
|
}
|
|
7677
7783
|
}
|
|
7678
7784
|
buildDirective(goal, source, task) {
|
|
7785
|
+
const recentJournal = goal.journal.slice(-5).map((e) => ` #${e.iteration} [${e.status}] ${e.task}${e.note ? ` \u2014 ${e.note.slice(0, 80)}` : ""}`).join("\n");
|
|
7679
7786
|
return [
|
|
7680
|
-
"
|
|
7787
|
+
"\u2550\u2550\u2550 ETERNAL AUTONOMY \u2014 iteration directive \u2550\u2550\u2550",
|
|
7681
7788
|
"",
|
|
7682
|
-
`
|
|
7789
|
+
`Mission: ${goal.goal}`,
|
|
7790
|
+
`Iteration: #${goal.iterations + 1}`,
|
|
7683
7791
|
`Source: ${source}`,
|
|
7684
7792
|
`Task: ${task}`,
|
|
7685
7793
|
"",
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
"
|
|
7689
|
-
"
|
|
7794
|
+
recentJournal ? `Recent journal (last 5):
|
|
7795
|
+
${recentJournal}` : "No prior iterations.",
|
|
7796
|
+
"",
|
|
7797
|
+
"\u2500\u2500 EXECUTION PROTOCOL \u2500\u2500",
|
|
7798
|
+
"You are inside a long-running autonomous loop. Each iteration you",
|
|
7799
|
+
"execute ONE concrete task that advances the Mission. No user is",
|
|
7800
|
+
"available to clarify \u2014 make defensible decisions and move forward.",
|
|
7801
|
+
"",
|
|
7802
|
+
"1. EXECUTE END-TO-END",
|
|
7803
|
+
" \u2022 Use multiple tool calls freely. Emit `[continue]` on its own line",
|
|
7804
|
+
" to chain to the next internal step without returning.",
|
|
7805
|
+
" \u2022 When this iteration's Task is finished (real artifact / passing",
|
|
7806
|
+
" test / applied diff / clean output), emit `[done]` on its own line.",
|
|
7807
|
+
" \u2022 Do not stop on the first obstacle \u2014 try at least 3 distinct",
|
|
7808
|
+
" approaches before giving up. YOLO is active; no confirmations.",
|
|
7809
|
+
"",
|
|
7810
|
+
"2. UPDATE TODO STATE (when Source is `todo`)",
|
|
7811
|
+
" \u2022 Mark this todo `in_progress` via the todos tool before tool work.",
|
|
7812
|
+
" \u2022 Mark it `completed` on success, with a one-line outcome note.",
|
|
7813
|
+
" \u2022 If you cannot make progress after 2 distinct attempts, mark it",
|
|
7814
|
+
" `cancelled` with the obstacle. The loop will skip it next time.",
|
|
7815
|
+
"",
|
|
7816
|
+
"3. MISSION-COMPLETE PROTOCOL",
|
|
7817
|
+
" \u2022 If \u2014 and ONLY if \u2014 the OVERALL Mission (not just this Task) is",
|
|
7818
|
+
" verifiably accomplished, emit on its own line:",
|
|
7819
|
+
" [GOAL_COMPLETE]",
|
|
7820
|
+
" followed by a one-paragraph verification recipe (artifact path,",
|
|
7821
|
+
" test command, or 10-second reproduction). This halts the loop.",
|
|
7822
|
+
" \u2022 NEVER emit [GOAL_COMPLETE] on optimism, partial progress, or",
|
|
7823
|
+
' "looks fine". Required: a concrete artifact that proves it AND',
|
|
7824
|
+
" no recent journal failures contradicting completion.",
|
|
7825
|
+
" \u2022 If unsure, emit `[done]` instead and let the next iteration",
|
|
7826
|
+
" decide. The loop is patient; false completion is not.",
|
|
7827
|
+
"",
|
|
7828
|
+
"4. NO INTERACTIVITY",
|
|
7829
|
+
" \u2022 Do not ask questions, do not request confirmation, do not propose",
|
|
7830
|
+
" options. Pick the best path and execute. The user is asleep."
|
|
7690
7831
|
].join("\n");
|
|
7691
7832
|
}
|
|
7833
|
+
/**
|
|
7834
|
+
* Exponential backoff for transient provider errors. `2^N * base`
|
|
7835
|
+
* capped at `transientBackoffMaxMs`. Zero base disables backoff.
|
|
7836
|
+
* Public-private to keep `runOneIteration` readable; the value is
|
|
7837
|
+
* recomputed each call from the current retry count, so callers
|
|
7838
|
+
* don't have to track state.
|
|
7839
|
+
*/
|
|
7840
|
+
computeTransientBackoffMs() {
|
|
7841
|
+
const base = this.opts.transientBackoffBaseMs ?? 2e3;
|
|
7842
|
+
const cap = this.opts.transientBackoffMaxMs ?? 6e4;
|
|
7843
|
+
if (base <= 0) return 0;
|
|
7844
|
+
const exponent = Math.max(0, this.consecutiveTransientRetries - 1);
|
|
7845
|
+
return Math.min(cap, base * Math.pow(2, exponent));
|
|
7846
|
+
}
|
|
7847
|
+
/**
|
|
7848
|
+
* Sleep that wakes early if `stopRequested` flips. Polls every 250 ms
|
|
7849
|
+
* so SIGINT / `/autonomy stop` can land in the middle of a long
|
|
7850
|
+
* backoff instead of waiting up to a minute for the timer.
|
|
7851
|
+
*/
|
|
7852
|
+
async sleepInterruptible(totalMs) {
|
|
7853
|
+
const step = 250;
|
|
7854
|
+
let remaining = totalMs;
|
|
7855
|
+
while (remaining > 0 && !this.stopRequested) {
|
|
7856
|
+
const chunk = Math.min(step, remaining);
|
|
7857
|
+
await sleep(chunk);
|
|
7858
|
+
remaining -= chunk;
|
|
7859
|
+
}
|
|
7860
|
+
}
|
|
7692
7861
|
async appendIterationEntry(entry) {
|
|
7693
7862
|
const current = await loadGoal(this.goalPath);
|
|
7694
7863
|
if (!current) {
|
|
@@ -7697,6 +7866,39 @@ ${lastFew}` : "No prior iterations yet.",
|
|
|
7697
7866
|
const updated = appendJournal(current, entry);
|
|
7698
7867
|
await saveGoal(this.goalPath, updated);
|
|
7699
7868
|
}
|
|
7869
|
+
/**
|
|
7870
|
+
* Persistent per-todo failure counter. Skipped silently when the goal
|
|
7871
|
+
* file has been removed (graceful clear). Each non-success iteration
|
|
7872
|
+
* against a todo source bumps the counter by 1; `pickPendingTodo` reads
|
|
7873
|
+
* the counter to rotate past stuck todos once they cross `todoMaxAttempts`.
|
|
7874
|
+
*/
|
|
7875
|
+
async bumpTodoAttempt(todoId) {
|
|
7876
|
+
const current = await loadGoal(this.goalPath);
|
|
7877
|
+
if (!current) return;
|
|
7878
|
+
const attempts = { ...current.todoAttempts ?? {} };
|
|
7879
|
+
attempts[todoId] = (attempts[todoId] ?? 0) + 1;
|
|
7880
|
+
await saveGoal(this.goalPath, { ...current, todoAttempts: attempts });
|
|
7881
|
+
}
|
|
7882
|
+
/**
|
|
7883
|
+
* Flip the mission to `completed` and journal it. Called from two
|
|
7884
|
+
* paths: (a) `[GOAL_COMPLETE]` marker in a successful iteration's
|
|
7885
|
+
* finalText, (b) `brainstorm` returning DONE consecutively past the
|
|
7886
|
+
* configured threshold. Idempotent — re-entry is a no-op once the
|
|
7887
|
+
* goal is already `completed`.
|
|
7888
|
+
*/
|
|
7889
|
+
async markGoalCompleted(action, note) {
|
|
7890
|
+
const current = await loadGoal(this.goalPath);
|
|
7891
|
+
if (!current) return;
|
|
7892
|
+
if (current.goalState === "completed") return;
|
|
7893
|
+
const withFlag = { ...current, goalState: "completed" };
|
|
7894
|
+
const withEntry = appendJournal(withFlag, {
|
|
7895
|
+
source: action.source,
|
|
7896
|
+
task: `MISSION COMPLETE \u2014 ${action.task}`.slice(0, 240),
|
|
7897
|
+
status: "success",
|
|
7898
|
+
note: note.slice(0, 240)
|
|
7899
|
+
});
|
|
7900
|
+
await saveGoal(this.goalPath, withEntry);
|
|
7901
|
+
}
|
|
7700
7902
|
async appendFailure(task, note) {
|
|
7701
7903
|
await this.appendIterationEntry({ source: "manual", task, status: "failure", note });
|
|
7702
7904
|
}
|
|
@@ -7711,6 +7913,142 @@ function sleep(ms) {
|
|
|
7711
7913
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
7712
7914
|
}
|
|
7713
7915
|
|
|
7916
|
+
// src/execution/autonomy-prompt-contributor.ts
|
|
7917
|
+
function makeAutonomyPromptContributor(opts) {
|
|
7918
|
+
return async (ctx) => {
|
|
7919
|
+
if (ctx.subagent) return [];
|
|
7920
|
+
if (!opts.enabled()) return [];
|
|
7921
|
+
let goal;
|
|
7922
|
+
try {
|
|
7923
|
+
goal = await loadGoal(opts.goalPath);
|
|
7924
|
+
} catch {
|
|
7925
|
+
return [];
|
|
7926
|
+
}
|
|
7927
|
+
if (!goal) return [];
|
|
7928
|
+
const missionState = goal.goalState ?? "active";
|
|
7929
|
+
if (missionState !== "active") return [];
|
|
7930
|
+
const tailSize = opts.journalTailSize ?? 5;
|
|
7931
|
+
const journalTail = goal.journal.slice(-tailSize).map((e) => {
|
|
7932
|
+
const note = e.note ? ` \u2014 ${e.note.slice(0, 80)}` : "";
|
|
7933
|
+
return ` #${e.iteration} [${e.status}] ${e.task}${note}`;
|
|
7934
|
+
});
|
|
7935
|
+
const text = [
|
|
7936
|
+
"## ETERNAL AUTONOMY \u2014 active mission",
|
|
7937
|
+
"",
|
|
7938
|
+
"You are inside a long-running autonomous loop. The user is asleep",
|
|
7939
|
+
"and is not available to confirm decisions. Each turn you receive a",
|
|
7940
|
+
"directive describing one concrete sub-task that advances the mission.",
|
|
7941
|
+
"",
|
|
7942
|
+
`Mission: ${goal.goal}`,
|
|
7943
|
+
`Iteration: #${goal.iterations}`,
|
|
7944
|
+
journalTail.length > 0 ? `Recent journal (last ${journalTail.length}):
|
|
7945
|
+
${journalTail.join("\n")}` : "Recent journal: (none \u2014 this is the first iteration)",
|
|
7946
|
+
"",
|
|
7947
|
+
"### Loop control markers",
|
|
7948
|
+
"Emit these on their own line in your final text \u2014 case-insensitive,",
|
|
7949
|
+
"whitespace-tolerant, but they must occupy the entire line:",
|
|
7950
|
+
"- `[continue]` \u2014 chain to the next internal step without returning.",
|
|
7951
|
+
"- `[done]` \u2014 the current sub-task is finished; return to the engine.",
|
|
7952
|
+
"- `[GOAL_COMPLETE]` \u2014 emit ONLY when the OVERALL mission is",
|
|
7953
|
+
" verifiably done. Must be followed by a one-paragraph verification",
|
|
7954
|
+
" recipe (artifact path, test command, or 10-second reproduction).",
|
|
7955
|
+
" The engine halts on this marker \u2014 false positives waste real",
|
|
7956
|
+
" human time. If unsure, emit `[done]` and let the next iteration",
|
|
7957
|
+
" decide.",
|
|
7958
|
+
"",
|
|
7959
|
+
"### Operating principles",
|
|
7960
|
+
"- YOLO is active. Do NOT ask for confirmation, do NOT propose",
|
|
7961
|
+
" options. Pick the best path and execute it.",
|
|
7962
|
+
"- Use tools freely; multiple calls per turn are normal and expected.",
|
|
7963
|
+
"- When working on a todo, mark it `in_progress` via the todos tool",
|
|
7964
|
+
" before tool work and `completed` (or `cancelled` with a reason)",
|
|
7965
|
+
" when done. The loop reads todo state between iterations.",
|
|
7966
|
+
"- If an approach fails twice in a row, pivot. Don't grind on the",
|
|
7967
|
+
" same wall \u2014 try a different angle, file a cancel on the todo, or",
|
|
7968
|
+
" surface the obstacle via `[done]` and let the next iteration",
|
|
7969
|
+
" re-plan."
|
|
7970
|
+
].join("\n");
|
|
7971
|
+
return [
|
|
7972
|
+
{
|
|
7973
|
+
type: "text",
|
|
7974
|
+
text,
|
|
7975
|
+
cache_control: { type: "ephemeral" }
|
|
7976
|
+
}
|
|
7977
|
+
];
|
|
7978
|
+
};
|
|
7979
|
+
}
|
|
7980
|
+
|
|
7981
|
+
// src/execution/goal-preamble.ts
|
|
7982
|
+
function buildGoalPreamble(goal) {
|
|
7983
|
+
return [
|
|
7984
|
+
"[GOAL \u2014 LOCKED IN. You will work on this until it is verifiably done.",
|
|
7985
|
+
"The user granted you full autonomy. Read these constraints once, then act.",
|
|
7986
|
+
"",
|
|
7987
|
+
"YOUR GOAL:",
|
|
7988
|
+
"---",
|
|
7989
|
+
goal,
|
|
7990
|
+
"---",
|
|
7991
|
+
"",
|
|
7992
|
+
"AUTHORITY YOU HAVE:",
|
|
7993
|
+
"- Spawn as many subagents as the work needs (delegate / spawn_subagent).",
|
|
7994
|
+
" Parallel + recursive fan-out are both fine. There is no spawn budget.",
|
|
7995
|
+
"- Use any provider/model per subagent \u2014 pick the right tool for each",
|
|
7996
|
+
" piece of work. Heavy reasoning model for planning, fast model for",
|
|
7997
|
+
" batch work, specialist model for domain code.",
|
|
7998
|
+
"- Run unlimited tool calls and iterations. There is NO hidden budget.",
|
|
7999
|
+
" The Agent loop auto-extends every 100 iterations forever.",
|
|
8000
|
+
"- Retry failed tools with different inputs, alternative paths, fresh",
|
|
8001
|
+
" subagents. Switch providers mid-run if one is rate-limited.",
|
|
8002
|
+
"- Re-plan freely when an approach hits a dead end. You are not obliged",
|
|
8003
|
+
" to stick with the first plan you proposed.",
|
|
8004
|
+
"",
|
|
8005
|
+
'WHAT "DONE" MEANS \u2014 non-negotiable:',
|
|
8006
|
+
"- You can name a concrete artifact (a passing test, a written file at",
|
|
8007
|
+
" a specific path, a fixed bug verified by re-running the failing case,",
|
|
8008
|
+
" a clean grep that previously had matches).",
|
|
8009
|
+
"- You can tell the user HOW to verify it themselves in 10 seconds.",
|
|
8010
|
+
'- You have NOT hedged. None of: "looks like it should work", "I',
|
|
8011
|
+
' believe this fixes it", "the changes appear correct".',
|
|
8012
|
+
"",
|
|
8013
|
+
"WHAT IS NOT DONE \u2014 never report any of these as completion:",
|
|
8014
|
+
"- An error message you didn't recover from.",
|
|
8015
|
+
'- An empty result, a 0-line file, a "no matches found" you accepted',
|
|
8016
|
+
" without questioning the search.",
|
|
8017
|
+
'- "Should I continue?" / "Want me to also...?" / "Let me know if you',
|
|
8018
|
+
' want X." Those are hedges. The user already told you to finish the',
|
|
8019
|
+
" goal \u2014 just do it.",
|
|
8020
|
+
"- Partial progress dressed up as success. Fixed 3 of 5 bugs = 60%",
|
|
8021
|
+
" done, not done.",
|
|
8022
|
+
"- A subagent's failed/timeout/stopped TaskResult that you didn't",
|
|
8023
|
+
" respond to with a fresh attempt (different role, different model,",
|
|
8024
|
+
" tighter prompt).",
|
|
8025
|
+
"",
|
|
8026
|
+
"PERSISTENCE PROTOCOL:",
|
|
8027
|
+
"- If blocked, try at least 3 different angles before reporting the",
|
|
8028
|
+
" problem to the user. Different tool inputs, different subagent",
|
|
8029
|
+
" roles, different providers, different decomposition of the task.",
|
|
8030
|
+
"- If a tool fails, read its error, alter the input, try again. Do",
|
|
8031
|
+
" not just report the failure back.",
|
|
8032
|
+
"- If a subagent returns useless output, respawn with a tighter prompt",
|
|
8033
|
+
' or a different role. Do not accept "I could not determine\u2026" as the',
|
|
8034
|
+
" final answer.",
|
|
8035
|
+
"- Use `ask_subagent` for one-shot questions when you don't need a",
|
|
8036
|
+
" full delegated task.",
|
|
8037
|
+
"",
|
|
8038
|
+
"REPORTING:",
|
|
8039
|
+
"- Stream short progress notes between major actions so the user can",
|
|
8040
|
+
" monitor. Do not go silent for 50 tool calls then dump a wall of",
|
|
8041
|
+
" text \u2014 but also do not narrate every tool call.",
|
|
8042
|
+
"- Use the shared scratchpad (if available) to leave breadcrumbs",
|
|
8043
|
+
" subagents can read.",
|
|
8044
|
+
"- Final response must include: (a) what was accomplished, (b) how",
|
|
8045
|
+
" to verify, (c) any caveats (residual TODOs, things the user",
|
|
8046
|
+
" should know about).",
|
|
8047
|
+
"",
|
|
8048
|
+
"BEGIN.]"
|
|
8049
|
+
].join("\n");
|
|
8050
|
+
}
|
|
8051
|
+
|
|
7714
8052
|
// src/coordination/director.ts
|
|
7715
8053
|
init_atomic_write();
|
|
7716
8054
|
|
|
@@ -8021,7 +8359,7 @@ var BudgetThresholdSignal = class extends Error {
|
|
|
8021
8359
|
this.decision = decision;
|
|
8022
8360
|
}
|
|
8023
8361
|
};
|
|
8024
|
-
var SubagentBudget = class {
|
|
8362
|
+
var SubagentBudget = class _SubagentBudget {
|
|
8025
8363
|
limits;
|
|
8026
8364
|
iterations = 0;
|
|
8027
8365
|
toolCalls = 0;
|
|
@@ -8030,6 +8368,26 @@ var SubagentBudget = class {
|
|
|
8030
8368
|
costUsd = 0;
|
|
8031
8369
|
startTime = null;
|
|
8032
8370
|
_onThreshold;
|
|
8371
|
+
/**
|
|
8372
|
+
* Tracks which budget kinds currently have an extension request
|
|
8373
|
+
* in flight. While a kind is here, further `checkLimit` calls for the
|
|
8374
|
+
* same kind are no-ops — without this dedup, every `recordIteration`
|
|
8375
|
+
* after the limit is reached spawns a fresh decision Promise (until
|
|
8376
|
+
* the first one lands and patches limits), flooding the FleetBus
|
|
8377
|
+
* with redundant threshold events. Cleared in `checkLimitAsync`'s
|
|
8378
|
+
* `finally`.
|
|
8379
|
+
*/
|
|
8380
|
+
pendingExtensions = /* @__PURE__ */ new Set();
|
|
8381
|
+
/**
|
|
8382
|
+
* Hard cap on how long `checkLimitAsync` waits for the coordinator to
|
|
8383
|
+
* respond before defaulting to 'stop'. Without this fallback an absent
|
|
8384
|
+
* or hung listener (Director not built / event filter detached mid-run)
|
|
8385
|
+
* leaves the budget over-limit and never enforces anything, since
|
|
8386
|
+
* `checkLimit` returns synchronously via `void this.checkLimitAsync`.
|
|
8387
|
+
* Hardcoded for now — most fleets set their own per-task timeout that
|
|
8388
|
+
* dwarfs this anyway. 30 s matches the existing event-emit timeoutMs.
|
|
8389
|
+
*/
|
|
8390
|
+
static DECISION_TIMEOUT_MS = 3e4;
|
|
8033
8391
|
/**
|
|
8034
8392
|
* Injected by the runner when wiring the budget to its EventBus.
|
|
8035
8393
|
* Used by `checkLimitAsync` to emit `budget.threshold_reached` events.
|
|
@@ -8072,56 +8430,92 @@ var SubagentBudget = class {
|
|
|
8072
8430
|
if (kind === "timeout" || !this._onThreshold) {
|
|
8073
8431
|
throw new BudgetExceededError(kind, limit, used);
|
|
8074
8432
|
}
|
|
8075
|
-
|
|
8433
|
+
const bus = this._events;
|
|
8434
|
+
if (!bus || bus.listenerCount("budget.threshold_reached") === 0) {
|
|
8435
|
+
throw new BudgetExceededError(kind, limit, used);
|
|
8436
|
+
}
|
|
8437
|
+
if (this.pendingExtensions.has(kind)) return;
|
|
8438
|
+
this.pendingExtensions.add(kind);
|
|
8439
|
+
const decision = this.negotiateExtension(kind, used, limit);
|
|
8440
|
+
throw new BudgetThresholdSignal(kind, limit, used, decision);
|
|
8076
8441
|
}
|
|
8077
8442
|
/**
|
|
8078
|
-
*
|
|
8079
|
-
*
|
|
8080
|
-
*
|
|
8443
|
+
* Drive the threshold handler to a decision. Resolves with `'stop'`
|
|
8444
|
+
* (signal the runner to abort) or `{ extend: ... }` (limits already
|
|
8445
|
+
* patched in-place; the runner should not abort). Always releases the
|
|
8446
|
+
* `pendingExtensions` slot in `finally`.
|
|
8447
|
+
*
|
|
8448
|
+
* The 'continue' return from a sync handler is treated as
|
|
8449
|
+
* `{ extend: {} }` — keep going without patching, next overrun will
|
|
8450
|
+
* fire a fresh signal.
|
|
8081
8451
|
*/
|
|
8082
|
-
async
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8452
|
+
async negotiateExtension(kind, used, limit) {
|
|
8453
|
+
try {
|
|
8454
|
+
const result = this._onThreshold({
|
|
8455
|
+
kind,
|
|
8456
|
+
used,
|
|
8457
|
+
limit,
|
|
8458
|
+
// Inject a requestDecision helper the handler can call to emit the
|
|
8459
|
+
// budget.threshold_reached event and wait for the coordinator's verdict.
|
|
8460
|
+
// A hard fallback timer guarantees the promise eventually resolves
|
|
8461
|
+
// even if no listener responds — without it, an absent/detached
|
|
8462
|
+
// Director would leave the budget permanently in "asking" state.
|
|
8463
|
+
requestDecision: () => {
|
|
8464
|
+
const bus = this._events;
|
|
8465
|
+
if (!bus || bus.listenerCount("budget.threshold_reached") === 0) {
|
|
8466
|
+
return Promise.resolve("stop");
|
|
8467
|
+
}
|
|
8468
|
+
return new Promise((resolve5) => {
|
|
8469
|
+
let resolved = false;
|
|
8470
|
+
const respond = (d) => {
|
|
8471
|
+
if (resolved) return;
|
|
8472
|
+
resolved = true;
|
|
8473
|
+
resolve5(d);
|
|
8474
|
+
};
|
|
8475
|
+
const fallback = setTimeout(
|
|
8476
|
+
() => respond("stop"),
|
|
8477
|
+
_SubagentBudget.DECISION_TIMEOUT_MS
|
|
8478
|
+
);
|
|
8479
|
+
bus.emit("budget.threshold_reached", {
|
|
8480
|
+
kind,
|
|
8481
|
+
used,
|
|
8482
|
+
limit,
|
|
8483
|
+
timeoutMs: _SubagentBudget.DECISION_TIMEOUT_MS,
|
|
8484
|
+
extend: (extra) => {
|
|
8485
|
+
clearTimeout(fallback);
|
|
8486
|
+
respond({ extend: extra });
|
|
8487
|
+
},
|
|
8488
|
+
deny: () => {
|
|
8489
|
+
clearTimeout(fallback);
|
|
8490
|
+
respond("stop");
|
|
8491
|
+
}
|
|
8492
|
+
});
|
|
8099
8493
|
});
|
|
8100
|
-
}
|
|
8494
|
+
}
|
|
8495
|
+
});
|
|
8496
|
+
if (result === "throw") return "stop";
|
|
8497
|
+
if (result === "continue") return { extend: {} };
|
|
8498
|
+
const decision = await result;
|
|
8499
|
+
if (decision === "stop") return "stop";
|
|
8500
|
+
const ext = decision.extend;
|
|
8501
|
+
if (ext.maxIterations !== void 0) {
|
|
8502
|
+
this.limits.maxIterations = ext.maxIterations;
|
|
8101
8503
|
}
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
if (ext.maxToolCalls !== void 0) {
|
|
8118
|
-
this.limits.maxToolCalls = ext.maxToolCalls;
|
|
8119
|
-
}
|
|
8120
|
-
if (ext.maxTokens !== void 0) {
|
|
8121
|
-
this.limits.maxTokens = ext.maxTokens;
|
|
8122
|
-
}
|
|
8123
|
-
if (ext.maxCostUsd !== void 0) {
|
|
8124
|
-
this.limits.maxCostUsd = ext.maxCostUsd;
|
|
8504
|
+
if (ext.maxToolCalls !== void 0) {
|
|
8505
|
+
this.limits.maxToolCalls = ext.maxToolCalls;
|
|
8506
|
+
}
|
|
8507
|
+
if (ext.maxTokens !== void 0) {
|
|
8508
|
+
this.limits.maxTokens = ext.maxTokens;
|
|
8509
|
+
}
|
|
8510
|
+
if (ext.maxCostUsd !== void 0) {
|
|
8511
|
+
this.limits.maxCostUsd = ext.maxCostUsd;
|
|
8512
|
+
}
|
|
8513
|
+
if (ext.timeoutMs !== void 0) {
|
|
8514
|
+
this.limits.timeoutMs = ext.timeoutMs;
|
|
8515
|
+
}
|
|
8516
|
+
return decision;
|
|
8517
|
+
} finally {
|
|
8518
|
+
this.pendingExtensions.delete(kind);
|
|
8125
8519
|
}
|
|
8126
8520
|
}
|
|
8127
8521
|
recordIteration() {
|
|
@@ -8404,6 +8798,19 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
8404
8798
|
setRunner(runner) {
|
|
8405
8799
|
this.runner = runner;
|
|
8406
8800
|
}
|
|
8801
|
+
/**
|
|
8802
|
+
* Change the in-flight dispatch ceiling at runtime. Lowering does NOT
|
|
8803
|
+
* preempt running tasks — already-dispatched subagents finish their
|
|
8804
|
+
* current task; only future dispatches respect the new cap. Raising
|
|
8805
|
+
* immediately tries to fill the freed slots from the pending queue.
|
|
8806
|
+
*/
|
|
8807
|
+
setMaxConcurrent(n) {
|
|
8808
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
8809
|
+
throw new Error(`maxConcurrent must be a finite integer >= 1, got ${n}`);
|
|
8810
|
+
}
|
|
8811
|
+
this.config.maxConcurrent = Math.floor(n);
|
|
8812
|
+
this.tryDispatchNext();
|
|
8813
|
+
}
|
|
8407
8814
|
async spawn(subagent) {
|
|
8408
8815
|
const id = subagent.id || randomUUID();
|
|
8409
8816
|
if (this.subagents.has(id)) {
|
|
@@ -8663,14 +9070,65 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
8663
9070
|
this.recordCompletion(result);
|
|
8664
9071
|
}
|
|
8665
9072
|
async executeWithTimeout(runner, task, ctx, budget) {
|
|
8666
|
-
const
|
|
8667
|
-
if (
|
|
9073
|
+
const initialTimeoutMs = budget.limits.timeoutMs;
|
|
9074
|
+
if (initialTimeoutMs === void 0) return runner(task, ctx);
|
|
9075
|
+
const start = Date.now();
|
|
8668
9076
|
let timer = null;
|
|
8669
9077
|
const timeoutPromise = new Promise((_, reject) => {
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
9078
|
+
const armFor = (ms) => {
|
|
9079
|
+
if (timer) clearTimeout(timer);
|
|
9080
|
+
timer = setTimeout(async () => {
|
|
9081
|
+
const elapsed = Date.now() - start;
|
|
9082
|
+
const limit = budget.limits.timeoutMs ?? initialTimeoutMs;
|
|
9083
|
+
if (!budget.onThreshold) {
|
|
9084
|
+
this.subagents.get(ctx.subagentId)?.abortController.abort();
|
|
9085
|
+
reject(new BudgetExceededError("timeout", limit, elapsed));
|
|
9086
|
+
return;
|
|
9087
|
+
}
|
|
9088
|
+
try {
|
|
9089
|
+
const result = budget.onThreshold({
|
|
9090
|
+
kind: "timeout",
|
|
9091
|
+
used: elapsed,
|
|
9092
|
+
limit,
|
|
9093
|
+
requestDecision: () => new Promise((resolveDecision) => {
|
|
9094
|
+
budget._events?.emit("budget.threshold_reached", {
|
|
9095
|
+
kind: "timeout",
|
|
9096
|
+
used: elapsed,
|
|
9097
|
+
limit,
|
|
9098
|
+
timeoutMs: 3e4,
|
|
9099
|
+
extend: (extra) => resolveDecision({ extend: extra }),
|
|
9100
|
+
deny: () => resolveDecision("stop")
|
|
9101
|
+
});
|
|
9102
|
+
})
|
|
9103
|
+
});
|
|
9104
|
+
const decision = typeof result === "string" ? result : await result;
|
|
9105
|
+
if (decision === "continue") {
|
|
9106
|
+
armFor(Math.max(1e3, limit));
|
|
9107
|
+
return;
|
|
9108
|
+
}
|
|
9109
|
+
if (decision === "throw" || decision === "stop") {
|
|
9110
|
+
this.subagents.get(ctx.subagentId)?.abortController.abort();
|
|
9111
|
+
reject(new BudgetExceededError("timeout", limit, elapsed));
|
|
9112
|
+
return;
|
|
9113
|
+
}
|
|
9114
|
+
if (decision.extend.timeoutMs !== void 0) {
|
|
9115
|
+
budget.limits.timeoutMs = decision.extend.timeoutMs;
|
|
9116
|
+
const newLimit = decision.extend.timeoutMs;
|
|
9117
|
+
const remaining = Math.max(1e3, newLimit - elapsed);
|
|
9118
|
+
armFor(remaining);
|
|
9119
|
+
return;
|
|
9120
|
+
}
|
|
9121
|
+
this.subagents.get(ctx.subagentId)?.abortController.abort();
|
|
9122
|
+
reject(new BudgetExceededError("timeout", limit, elapsed));
|
|
9123
|
+
} catch (err) {
|
|
9124
|
+
this.subagents.get(ctx.subagentId)?.abortController.abort();
|
|
9125
|
+
reject(
|
|
9126
|
+
err instanceof BudgetExceededError ? err : new BudgetExceededError("timeout", limit, elapsed)
|
|
9127
|
+
);
|
|
9128
|
+
}
|
|
9129
|
+
}, ms);
|
|
9130
|
+
};
|
|
9131
|
+
armFor(initialTimeoutMs);
|
|
8674
9132
|
});
|
|
8675
9133
|
try {
|
|
8676
9134
|
return await Promise.race([runner(task, ctx), timeoutPromise]);
|
|
@@ -9281,7 +9739,7 @@ var Director = class {
|
|
|
9281
9739
|
return;
|
|
9282
9740
|
}
|
|
9283
9741
|
extendCounts.set(guardKey, prior + 1);
|
|
9284
|
-
|
|
9742
|
+
setImmediate(() => {
|
|
9285
9743
|
const extra = {};
|
|
9286
9744
|
switch (payload.kind) {
|
|
9287
9745
|
case "iterations":
|
|
@@ -9296,9 +9754,12 @@ var Director = class {
|
|
|
9296
9754
|
case "cost":
|
|
9297
9755
|
extra.maxCostUsd = Math.min(payload.limit * 1.5, 10);
|
|
9298
9756
|
break;
|
|
9757
|
+
case "timeout":
|
|
9758
|
+
extra.timeoutMs = Math.min(Math.ceil(payload.limit * 1.5), 60 * 6e4);
|
|
9759
|
+
break;
|
|
9299
9760
|
}
|
|
9300
9761
|
payload.extend(extra);
|
|
9301
|
-
}
|
|
9762
|
+
});
|
|
9302
9763
|
});
|
|
9303
9764
|
}
|
|
9304
9765
|
/** Best-effort session-writer append. Swallows failures — the director
|
|
@@ -10093,6 +10554,7 @@ function makeAgentSubagentRunner(opts) {
|
|
|
10093
10554
|
const detachFleet = opts.fleetBus?.attach(ctx.subagentId, events, task.id);
|
|
10094
10555
|
const aborter = new AbortController();
|
|
10095
10556
|
ctx.budget._events = events;
|
|
10557
|
+
ctx.budget.onThreshold = ({ requestDecision }) => requestDecision();
|
|
10096
10558
|
let budgetError = null;
|
|
10097
10559
|
const onBudgetError = (err) => {
|
|
10098
10560
|
if (err instanceof BudgetThresholdSignal) {
|
|
@@ -16118,16 +16580,16 @@ Use \`/security report <number>\` to view a specific report.` };
|
|
|
16118
16580
|
}
|
|
16119
16581
|
const index = parseInt(reportId, 10) - 1;
|
|
16120
16582
|
if (!isNaN(index) && reports[index]) {
|
|
16121
|
-
const { readFile:
|
|
16122
|
-
const content = await
|
|
16583
|
+
const { readFile: readFile30 } = await import('fs/promises');
|
|
16584
|
+
const content = await readFile30(join(reportsDir, reports[index]), "utf-8");
|
|
16123
16585
|
return { message: `# Security Report
|
|
16124
16586
|
|
|
16125
16587
|
${content}` };
|
|
16126
16588
|
}
|
|
16127
16589
|
const match = reports.find((r) => r.includes(reportId));
|
|
16128
16590
|
if (match) {
|
|
16129
|
-
const { readFile:
|
|
16130
|
-
const content = await
|
|
16591
|
+
const { readFile: readFile30 } = await import('fs/promises');
|
|
16592
|
+
const content = await readFile30(join(reportsDir, match), "utf-8");
|
|
16131
16593
|
return { message: `# Security Report
|
|
16132
16594
|
|
|
16133
16595
|
${content}` };
|
|
@@ -16382,6 +16844,226 @@ var FleetManager = class {
|
|
|
16382
16844
|
return { pending, live: [] };
|
|
16383
16845
|
}
|
|
16384
16846
|
};
|
|
16847
|
+
function createMcpControlTool(opts) {
|
|
16848
|
+
const { getConfig, configPath, registry } = opts;
|
|
16849
|
+
const inputSchema = {
|
|
16850
|
+
type: "object",
|
|
16851
|
+
properties: {
|
|
16852
|
+
action: {
|
|
16853
|
+
type: "string",
|
|
16854
|
+
enum: ["list", "search", "enable", "disable", "restart"],
|
|
16855
|
+
description: "The management action to perform."
|
|
16856
|
+
},
|
|
16857
|
+
/** Filter for `search`. Matches server name or description case-insensitively. */
|
|
16858
|
+
query: {
|
|
16859
|
+
type: "string",
|
|
16860
|
+
description: "Search term for `search` action. Matches server name or description."
|
|
16861
|
+
},
|
|
16862
|
+
/** Target server name for `enable`, `disable`, `restart`. */
|
|
16863
|
+
server: {
|
|
16864
|
+
type: "string",
|
|
16865
|
+
description: 'Server name (e.g. "github", "filesystem", "brave-search").'
|
|
16866
|
+
}
|
|
16867
|
+
},
|
|
16868
|
+
required: ["action"]
|
|
16869
|
+
};
|
|
16870
|
+
return {
|
|
16871
|
+
name: "mcp_control",
|
|
16872
|
+
description: "Manage MCP server lifecycle: list available servers, search by name or capability, enable or disable servers at runtime, restart running servers.",
|
|
16873
|
+
category: "mcp",
|
|
16874
|
+
permission: "auto",
|
|
16875
|
+
mutating: false,
|
|
16876
|
+
riskTier: "standard",
|
|
16877
|
+
inputSchema,
|
|
16878
|
+
async execute(raw, ctx) {
|
|
16879
|
+
const input = raw;
|
|
16880
|
+
return mcpControlDispatch(input, { getConfig, configPath, registry });
|
|
16881
|
+
}
|
|
16882
|
+
};
|
|
16883
|
+
}
|
|
16884
|
+
async function mcpControlDispatch(input, deps) {
|
|
16885
|
+
const { action, query, server } = input;
|
|
16886
|
+
switch (action) {
|
|
16887
|
+
case "list":
|
|
16888
|
+
return renderList(deps);
|
|
16889
|
+
case "search":
|
|
16890
|
+
return renderSearch(query ?? "", deps);
|
|
16891
|
+
case "enable":
|
|
16892
|
+
return runEnable(server, deps);
|
|
16893
|
+
case "disable":
|
|
16894
|
+
return runDisable(server, deps);
|
|
16895
|
+
case "restart":
|
|
16896
|
+
return runRestart(server, deps);
|
|
16897
|
+
default:
|
|
16898
|
+
return `Unknown action "${action}". Use one of: list, search, enable, disable, restart.`;
|
|
16899
|
+
}
|
|
16900
|
+
}
|
|
16901
|
+
function renderList(deps) {
|
|
16902
|
+
const configured = deps.getConfig().mcpServers ?? {};
|
|
16903
|
+
const live = deps.registry.describe();
|
|
16904
|
+
if (Object.keys(configured).length === 0) {
|
|
16905
|
+
return [
|
|
16906
|
+
"No MCP servers configured.",
|
|
16907
|
+
' Use `mcp_control({ action: "search" })` to see available presets,',
|
|
16908
|
+
' then `mcp_control({ action: "enable", server: "<name>" })` to add one.'
|
|
16909
|
+
].join("\n");
|
|
16910
|
+
}
|
|
16911
|
+
const lines = [];
|
|
16912
|
+
const liveMap = new Map(live.map((s) => [s.name, s]));
|
|
16913
|
+
for (const [name, cfg] of Object.entries(configured)) {
|
|
16914
|
+
const liveInfo = liveMap.get(name);
|
|
16915
|
+
const toolCount = liveInfo ? ` (${liveInfo.toolCount} tools)` : "";
|
|
16916
|
+
const stateStr = liveInfo ? badge(liveInfo.state) : dim("\u25CB not loaded");
|
|
16917
|
+
const enabled = cfg.enabled === false ? `${dim("disabled")} ` : `${green("\u25CF enabled")} `;
|
|
16918
|
+
lines.push(` ${bold(name)} ${enabled}${stateStr}${toolCount}`);
|
|
16919
|
+
if (cfg.description) lines.push(` ${dim(cfg.description)}`);
|
|
16920
|
+
}
|
|
16921
|
+
lines.push("");
|
|
16922
|
+
lines.push(dim(' Use `mcp_control({ action: "search", query: "<keyword>" })` to find servers.'));
|
|
16923
|
+
lines.push(dim(' Use `mcp_control({ action: "enable", server: "<name>" })` to start a server.'));
|
|
16924
|
+
return lines.join("\n");
|
|
16925
|
+
}
|
|
16926
|
+
function renderSearch(query, deps) {
|
|
16927
|
+
const configured = deps.getConfig().mcpServers ?? {};
|
|
16928
|
+
const all = allServers();
|
|
16929
|
+
const q = query.toLowerCase();
|
|
16930
|
+
const configuredNames = new Set(Object.keys(configured));
|
|
16931
|
+
const configuredEntries = Object.entries(configured).filter(
|
|
16932
|
+
([name, cfg]) => name.toLowerCase().includes(q) || (cfg.description ?? "").toLowerCase().includes(q)
|
|
16933
|
+
);
|
|
16934
|
+
const unconfiguredEntries = Object.entries(all).filter(([name]) => !configuredNames.has(name)).filter(
|
|
16935
|
+
([name, cfg]) => name.toLowerCase().includes(q) || (cfg.description ?? "").toLowerCase().includes(q)
|
|
16936
|
+
);
|
|
16937
|
+
const lines = [];
|
|
16938
|
+
if (configuredEntries.length > 0) {
|
|
16939
|
+
lines.push(bold('Configured servers matching "') + query + '":');
|
|
16940
|
+
for (const [name, cfg] of configuredEntries) {
|
|
16941
|
+
lines.push(` ${bold(name)} ${cfg.description ?? cfg.transport}`);
|
|
16942
|
+
}
|
|
16943
|
+
lines.push("");
|
|
16944
|
+
}
|
|
16945
|
+
if (unconfiguredEntries.length > 0) {
|
|
16946
|
+
lines.push(bold('Available presets matching "') + query + '":');
|
|
16947
|
+
for (const [name, cfg] of unconfiguredEntries) {
|
|
16948
|
+
const warn = cfg.permission === "deny" ? red(" \u26A0 confirm required") : "";
|
|
16949
|
+
lines.push(` ${bold(name)} ${cfg.description ?? cfg.transport}${warn}`);
|
|
16950
|
+
}
|
|
16951
|
+
lines.push("");
|
|
16952
|
+
}
|
|
16953
|
+
if (configuredEntries.length === 0 && unconfiguredEntries.length === 0) {
|
|
16954
|
+
return `No servers match "${query}". Try a shorter keyword or \`mcp_control({ action: "list" })\`.`;
|
|
16955
|
+
}
|
|
16956
|
+
const total = configuredEntries.length + unconfiguredEntries.length;
|
|
16957
|
+
lines.push(dim(` ${total} server${total !== 1 ? "s" : ""} shown. Run \`enable\` on one to activate it.`));
|
|
16958
|
+
return lines.join("\n");
|
|
16959
|
+
}
|
|
16960
|
+
async function runEnable(name, deps) {
|
|
16961
|
+
if (!name) return '`server` is required for enable. Example: { action: "enable", server: "github" }';
|
|
16962
|
+
const all = allServers();
|
|
16963
|
+
const configured = deps.getConfig().mcpServers ?? {};
|
|
16964
|
+
const cfg = configured[name] ?? all[name];
|
|
16965
|
+
if (!cfg) {
|
|
16966
|
+
const known = Object.keys(all).join(", ");
|
|
16967
|
+
return `Unknown server "${name}". Available presets: ${known}`;
|
|
16968
|
+
}
|
|
16969
|
+
const full = await readConfig(deps.configPath);
|
|
16970
|
+
const mcpServers = {
|
|
16971
|
+
...full.mcpServers ?? {}
|
|
16972
|
+
};
|
|
16973
|
+
mcpServers[name] = { ...cfg, enabled: true };
|
|
16974
|
+
full.mcpServers = mcpServers;
|
|
16975
|
+
await writeConfig(deps.configPath, full);
|
|
16976
|
+
try {
|
|
16977
|
+
const live = deps.registry.describe().find((s) => s.name === name);
|
|
16978
|
+
if (live && live.state === "connected") {
|
|
16979
|
+
return `${green("\u25CF")} Server "${name}" is already running (${live.toolCount} tools registered).`;
|
|
16980
|
+
}
|
|
16981
|
+
await deps.registry.start({ ...cfg, enabled: true });
|
|
16982
|
+
const updated = deps.registry.describe().find((s) => s.name === name);
|
|
16983
|
+
return `${green("\u2713 Enabled and started")} "${name}"${updated ? ` (${updated.toolCount} tools registered).` : "."}`;
|
|
16984
|
+
} catch (err) {
|
|
16985
|
+
return `${red("\u2717 Failed to start")} "${name}": ${err instanceof Error ? err.message : String(err)}`;
|
|
16986
|
+
}
|
|
16987
|
+
}
|
|
16988
|
+
async function runDisable(name, deps) {
|
|
16989
|
+
if (!name) return '`server` is required for disable. Example: { action: "disable", server: "github" }';
|
|
16990
|
+
const configured = deps.getConfig().mcpServers ?? {};
|
|
16991
|
+
if (!configured[name]) {
|
|
16992
|
+
return `Server "${name}" is not in config. Add it with \`mcp_control({ action: "enable", server: "${name}" })\`.`;
|
|
16993
|
+
}
|
|
16994
|
+
const full = await readConfig(deps.configPath);
|
|
16995
|
+
const mcpServers = {
|
|
16996
|
+
...full.mcpServers ?? {}
|
|
16997
|
+
};
|
|
16998
|
+
const existing = mcpServers[name];
|
|
16999
|
+
mcpServers[name] = { ...existing, enabled: false };
|
|
17000
|
+
full.mcpServers = mcpServers;
|
|
17001
|
+
await writeConfig(deps.configPath, full);
|
|
17002
|
+
try {
|
|
17003
|
+
await deps.registry.stop(name);
|
|
17004
|
+
return `${yellow("\u25CB Disabled")} "${name}". It will not be started on next boot.`;
|
|
17005
|
+
} catch {
|
|
17006
|
+
return `${yellow("\u25CB Disabled")} "${name}" (it was not running). Config updated.`;
|
|
17007
|
+
}
|
|
17008
|
+
}
|
|
17009
|
+
async function runRestart(name, deps) {
|
|
17010
|
+
if (!name) return '`server` is required for restart. Example: { action: "restart", server: "github" }';
|
|
17011
|
+
const configured = deps.getConfig().mcpServers ?? {};
|
|
17012
|
+
if (!configured[name]) {
|
|
17013
|
+
return `Server "${name}" is not configured. Use \`mcp_control({ action: "enable", server: "${name}" })\` first.`;
|
|
17014
|
+
}
|
|
17015
|
+
try {
|
|
17016
|
+
await deps.registry.restart(name);
|
|
17017
|
+
const updated = deps.registry.describe().find((s) => s.name === name);
|
|
17018
|
+
return `${green("\u2713 Restarted")} "${name}"${updated ? ` (${updated.toolCount} tools registered).` : "."}`;
|
|
17019
|
+
} catch (err) {
|
|
17020
|
+
return `${red("\u2717 Restart failed")} for "${name}": ${err instanceof Error ? err.message : String(err)}`;
|
|
17021
|
+
}
|
|
17022
|
+
}
|
|
17023
|
+
async function readConfig(p) {
|
|
17024
|
+
try {
|
|
17025
|
+
return JSON.parse(await fsp2.readFile(p, "utf8"));
|
|
17026
|
+
} catch {
|
|
17027
|
+
return {};
|
|
17028
|
+
}
|
|
17029
|
+
}
|
|
17030
|
+
async function writeConfig(p, cfg) {
|
|
17031
|
+
const raw = JSON.stringify(cfg, null, 2);
|
|
17032
|
+
const tmp = p + ".tmp";
|
|
17033
|
+
await fsp2.writeFile(tmp, raw, "utf8");
|
|
17034
|
+
await fsp2.rename(tmp, p);
|
|
17035
|
+
}
|
|
17036
|
+
function bold(s) {
|
|
17037
|
+
return `\x1B[1m${s}\x1B[0m`;
|
|
17038
|
+
}
|
|
17039
|
+
function dim(s) {
|
|
17040
|
+
return `\x1B[2m${s}\x1B[0m`;
|
|
17041
|
+
}
|
|
17042
|
+
function green(s) {
|
|
17043
|
+
return `\x1B[32m${s}\x1B[0m`;
|
|
17044
|
+
}
|
|
17045
|
+
function yellow(s) {
|
|
17046
|
+
return `\x1B[33m${s}\x1B[0m`;
|
|
17047
|
+
}
|
|
17048
|
+
function red(s) {
|
|
17049
|
+
return `\x1B[31m${s}\x1B[0m`;
|
|
17050
|
+
}
|
|
17051
|
+
function badge(state) {
|
|
17052
|
+
switch (state) {
|
|
17053
|
+
case "connected":
|
|
17054
|
+
return green("\u25CF connected");
|
|
17055
|
+
case "connecting":
|
|
17056
|
+
return `\x1B[36m\u25D0 connecting\x1B[0m`;
|
|
17057
|
+
case "reconnecting":
|
|
17058
|
+
return `\x1B[36m\u25D1 reconnecting\x1B[0m`;
|
|
17059
|
+
case "disconnected":
|
|
17060
|
+
return dim("\u25CB disconnected");
|
|
17061
|
+
case "failed":
|
|
17062
|
+
return red("\u2717 failed");
|
|
17063
|
+
default:
|
|
17064
|
+
return dim(state);
|
|
17065
|
+
}
|
|
17066
|
+
}
|
|
16385
17067
|
|
|
16386
17068
|
// src/extension/registry.ts
|
|
16387
17069
|
var ExtensionRegistry = class {
|
|
@@ -16844,6 +17526,7 @@ var Agent = class {
|
|
|
16844
17526
|
let effectiveLimit = opts.maxIterations ?? this.maxIterations;
|
|
16845
17527
|
const hasHardLimit = effectiveLimit > 0 && Number.isFinite(effectiveLimit);
|
|
16846
17528
|
let recoveryRetries = 0;
|
|
17529
|
+
const autonomousContinue = opts.autonomousContinue ?? this.autonomousContinue;
|
|
16847
17530
|
const diRunner = this.container.has(TOKENS.ProviderRunner) ? this.container.resolve(TOKENS.ProviderRunner) : null;
|
|
16848
17531
|
const baseRunner = diRunner ? (ctx, req) => diRunner.run({
|
|
16849
17532
|
provider: ctx.provider,
|
|
@@ -16870,7 +17553,7 @@ var Agent = class {
|
|
|
16870
17553
|
if (controller.signal.aborted) {
|
|
16871
17554
|
return { status: "aborted", iterations };
|
|
16872
17555
|
}
|
|
16873
|
-
if (
|
|
17556
|
+
if (autonomousContinue) {
|
|
16874
17557
|
consumeAutonomousContinue(this.ctx);
|
|
16875
17558
|
}
|
|
16876
17559
|
const limitCheck = await this.checkIterationLimit(
|
|
@@ -16949,18 +17632,18 @@ var Agent = class {
|
|
|
16949
17632
|
const toolUses = res.content.filter(isToolUseBlock);
|
|
16950
17633
|
if (toolUses.length === 0) {
|
|
16951
17634
|
this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
|
|
16952
|
-
if (
|
|
17635
|
+
if (autonomousContinue && responseResult.directive === "continue") {
|
|
16953
17636
|
await this.compactContextIfNeeded();
|
|
16954
17637
|
await this.extensions.runAfterIteration(this.ctx, i);
|
|
16955
17638
|
continue;
|
|
16956
17639
|
}
|
|
16957
|
-
if (
|
|
17640
|
+
if (autonomousContinue && responseResult.directive === "stop") {
|
|
16958
17641
|
return { status: "done", iterations, finalText };
|
|
16959
17642
|
}
|
|
16960
17643
|
return { status: "done", iterations, finalText };
|
|
16961
17644
|
}
|
|
16962
17645
|
await this.executeTools(toolUses);
|
|
16963
|
-
if (
|
|
17646
|
+
if (autonomousContinue && consumeAutonomousContinue(this.ctx)) {
|
|
16964
17647
|
this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
|
|
16965
17648
|
await this.compactContextIfNeeded();
|
|
16966
17649
|
await this.extensions.runAfterIteration(this.ctx, i);
|
|
@@ -16969,10 +17652,10 @@ var Agent = class {
|
|
|
16969
17652
|
this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
|
|
16970
17653
|
await this.compactContextIfNeeded();
|
|
16971
17654
|
await this.extensions.runAfterIteration(this.ctx, i);
|
|
16972
|
-
if (
|
|
17655
|
+
if (autonomousContinue && responseResult.directive === "continue") {
|
|
16973
17656
|
continue;
|
|
16974
17657
|
}
|
|
16975
|
-
if (
|
|
17658
|
+
if (autonomousContinue && responseResult.directive === "stop") {
|
|
16976
17659
|
return { status: "done", iterations, finalText };
|
|
16977
17660
|
}
|
|
16978
17661
|
}
|
|
@@ -17062,7 +17745,7 @@ var Agent = class {
|
|
|
17062
17745
|
}
|
|
17063
17746
|
}
|
|
17064
17747
|
let directive = "none";
|
|
17065
|
-
if (
|
|
17748
|
+
if (finalText) {
|
|
17066
17749
|
directive = parseContinueDirective(finalText);
|
|
17067
17750
|
}
|
|
17068
17751
|
return { finalText, aborted: false, done: false, directive };
|
|
@@ -18658,6 +19341,6 @@ function wrapApiForCapabilityCheck(plugin, api, log, enforce = false) {
|
|
|
18658
19341
|
});
|
|
18659
19342
|
}
|
|
18660
19343
|
|
|
18661
|
-
export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, atomicWrite, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildChildEnv, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatGoal, formatPlan, formatPlanTemplates, formatTodosList, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, goalFilePath, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeContinueToNextIterationTool, makeDirectorSessionFactory, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseContinueDirective, parseSkillRef, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, securitySlashCommand, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
|
|
19344
|
+
export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, atomicWrite, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildChildEnv, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMcpControlTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatGoal, formatPlan, formatPlanTemplates, formatTodosList, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, goalFilePath, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAutonomyPromptContributor, makeContinueToNextIterationTool, makeDirectorSessionFactory, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseContinueDirective, parseSkillRef, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, securitySlashCommand, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
|
|
18662
19345
|
//# sourceMappingURL=index.js.map
|
|
18663
19346
|
//# sourceMappingURL=index.js.map
|