@wrongstack/core 0.6.6 → 0.6.7

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.
Files changed (48) hide show
  1. package/dist/{agent-bridge-BBXK_ppx.d.ts → agent-bridge-BCVxmrOn.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-DsSm9lKN.d.ts → agent-subagent-runner-BTloSwjE.d.ts} +3 -3
  3. package/dist/{compactor-C8NhpSt5.d.ts → compactor-BUJ8550X.d.ts} +1 -1
  4. package/dist/{config-DfC6g6KV.d.ts → config-BHkYGzUT.d.ts} +1 -1
  5. package/dist/{context-DN5v-uQX.d.ts → context-C8mBUzBv.d.ts} +3 -5
  6. package/dist/coordination/index.d.ts +10 -10
  7. package/dist/coordination/index.js +62 -30
  8. package/dist/coordination/index.js.map +1 -1
  9. package/dist/defaults/index.d.ts +19 -19
  10. package/dist/defaults/index.js +94 -32
  11. package/dist/defaults/index.js.map +1 -1
  12. package/dist/{events-CJqwQl8G.d.ts → events-DounT6pP.d.ts} +10 -1
  13. package/dist/execution/index.d.ts +20 -12
  14. package/dist/execution/index.js +59 -18
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +6 -6
  17. package/dist/{index-CXnWsGBp.d.ts → index-BlVITqm-.d.ts} +6 -9
  18. package/dist/{index-DcnXDPdY.d.ts → index-DiIGZh5I.d.ts} +20 -5
  19. package/dist/index.d.ts +26 -26
  20. package/dist/index.js +212 -127
  21. package/dist/index.js.map +1 -1
  22. package/dist/infrastructure/index.d.ts +6 -6
  23. package/dist/kernel/index.d.ts +9 -9
  24. package/dist/kernel/index.js.map +1 -1
  25. package/dist/{mcp-servers-CevFHHM1.d.ts → mcp-servers-CXFfDN_d.d.ts} +3 -3
  26. package/dist/models/index.d.ts +2 -2
  27. package/dist/{multi-agent-D5IbASk_.d.ts → multi-agent-Iy8YUe3v.d.ts} +4 -4
  28. package/dist/observability/index.d.ts +2 -2
  29. package/dist/{path-resolver-CBx_q1HA.d.ts → path-resolver-DwJO5XBn.d.ts} +2 -2
  30. package/dist/{plan-templates-BEOllUJV.d.ts → plan-templates-CG_pInJV.d.ts} +4 -4
  31. package/dist/{provider-runner-Byh5TcJs.d.ts → provider-runner-DoohzfyD.d.ts} +3 -3
  32. package/dist/{retry-policy-BZSIMxrJ.d.ts → retry-policy-DOnwHAyz.d.ts} +1 -1
  33. package/dist/sdd/index.d.ts +3 -3
  34. package/dist/{secret-scrubber-CT7wefiO.d.ts → secret-scrubber-C9UJxFCJ.d.ts} +1 -1
  35. package/dist/{secret-scrubber-I0QHY_ob.d.ts → secret-scrubber-DcTK9JHC.d.ts} +1 -1
  36. package/dist/security/index.d.ts +3 -3
  37. package/dist/{selector-DDb_mq9X.d.ts → selector-DVo3eT-P.d.ts} +1 -1
  38. package/dist/{session-reader-B9nVkziM.d.ts → session-reader-BXWxFAhS.d.ts} +1 -1
  39. package/dist/storage/index.d.ts +5 -5
  40. package/dist/storage/index.js +1 -1
  41. package/dist/storage/index.js.map +1 -1
  42. package/dist/{system-prompt-gL06H9P4.d.ts → system-prompt-BBGles-N.d.ts} +1 -1
  43. package/dist/{tool-executor-BF7QfYVE.d.ts → tool-executor-CwpjhwHC.d.ts} +4 -4
  44. package/dist/types/index.d.ts +15 -15
  45. package/dist/types/index.js +1 -3
  46. package/dist/types/index.js.map +1 -1
  47. package/dist/utils/index.d.ts +1 -1
  48. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2558,10 +2558,8 @@ var InMemoryAgentBridge = class {
2558
2558
  this.pendingRequests.delete(correlationId);
2559
2559
  reject(new Error(`Request ${correlationId} timed out after ${timeout}ms`));
2560
2560
  }, timeout);
2561
- if (this.stopped) {
2561
+ if (!this.inflightGuards.has(correlationId)) {
2562
2562
  clearTimeout(timer);
2563
- this.inflightGuards.delete(correlationId);
2564
- this.pendingRequests.delete(correlationId);
2565
2563
  reject(new Error("Bridge stopped"));
2566
2564
  return;
2567
2565
  }
@@ -5745,7 +5743,7 @@ var DirectorStateCheckpoint = class {
5745
5743
  this.timer = null;
5746
5744
  }
5747
5745
  await this.persist();
5748
- if (this.rewriteRequested) {
5746
+ while (this.rewriteRequested) {
5749
5747
  this.rewriteRequested = false;
5750
5748
  await this.persist();
5751
5749
  }
@@ -7454,7 +7452,8 @@ function formatGoal(goal, journalLimit = 10) {
7454
7452
  // src/execution/eternal-autonomy.ts
7455
7453
  var execFileP = promisify(execFile);
7456
7454
  var BRAINSTORM_DONE = /* @__PURE__ */ Symbol("brainstorm-done");
7457
- var GOAL_COMPLETE_MARKER = /^\s*\[goal[_\s-]?complete\]\s*$/im;
7455
+ var GOAL_COMPLETE_MARKER = /^\s*\[goal[_\s-]*complete\]\s*$/im;
7456
+ var GOAL_CLEAR_MARKER = /^\s*\[\/?goal\s*clear\]\s*$/im;
7458
7457
  var EternalAutonomyEngine = class {
7459
7458
  constructor(opts) {
7460
7459
  this.opts = opts;
@@ -7680,7 +7679,12 @@ var EternalAutonomyEngine = class {
7680
7679
  emit({ phase: "sleep", ms: cycleGapMs });
7681
7680
  await sleep(cycleGapMs);
7682
7681
  if (GOAL_COMPLETE_MARKER.test(finalText)) {
7683
- await this.markGoalCompleted(action, finalText);
7682
+ await this.clearGoalManually(finalText);
7683
+ this.stopRequested = true;
7684
+ return true;
7685
+ }
7686
+ if (GOAL_CLEAR_MARKER.test(finalText)) {
7687
+ await this.clearGoalManually(finalText);
7684
7688
  this.stopRequested = true;
7685
7689
  return true;
7686
7690
  }
@@ -7980,6 +7984,30 @@ ${recentJournal}` : "No prior iterations.",
7980
7984
  });
7981
7985
  await saveGoal(this.goalPath, withEntry);
7982
7986
  }
7987
+ /**
7988
+ * Manually clear the goal — equivalent to `/goal clear` typed by the user.
7989
+ * Sets goalState to `abandoned`, removes the goal file, and fires
7990
+ * `onEternalStop` so the REPL returns to normal mode.
7991
+ */
7992
+ async clearGoalManually(note) {
7993
+ const current = await loadGoal(this.goalPath);
7994
+ if (current) {
7995
+ const abandoned = { ...current, goalState: "abandoned" };
7996
+ await saveGoal(this.goalPath, abandoned);
7997
+ }
7998
+ try {
7999
+ const { unlink: unlink10 } = await import('fs/promises');
8000
+ await unlink10(this.goalPath);
8001
+ } catch {
8002
+ }
8003
+ this.opts.onEternalStop?.();
8004
+ void this.appendIterationEntry({
8005
+ source: "manual",
8006
+ task: "goal cleared",
8007
+ status: "success",
8008
+ note: note.slice(0, 240)
8009
+ });
8010
+ }
7983
8011
  async appendFailure(task, note) {
7984
8012
  await this.appendIterationEntry({ source: "manual", task, status: "failure", note });
7985
8013
  }
@@ -8047,10 +8075,10 @@ var SubagentBudget = class _SubagentBudget {
8047
8075
  * or hung listener (Director not built / event filter detached mid-run)
8048
8076
  * leaves the budget over-limit and never enforces anything, since
8049
8077
  * `checkLimit` returns synchronously via `void this.checkLimitAsync`.
8050
- * Hardcoded for now most fleets set their own per-task timeout that
8051
- * dwarfs this anyway. 30 s matches the existing event-emit timeoutMs.
8078
+ * Raised from 30s to 60s to give subagents more headroom before
8079
+ * the threshold negotiation times out and triggers a hard stop.
8052
8080
  */
8053
- static DECISION_TIMEOUT_MS = 3e4;
8081
+ static DECISION_TIMEOUT_MS = 6e4;
8054
8082
  /**
8055
8083
  * Injected by the runner when wiring the budget to its EventBus.
8056
8084
  * Used by `checkLimitAsync` to emit `budget.threshold_reached` events.
@@ -8581,13 +8609,19 @@ var FLEET_ROSTER = {
8581
8609
  "security-scanner": SECURITY_SCANNER_AGENT
8582
8610
  };
8583
8611
  var FLEET_ROSTER_BUDGETS = {
8584
- "audit-log": { timeoutMs: 8 * 60 * 1e3, maxIterations: 150, maxToolCalls: 500 },
8585
- "bug-hunter": { timeoutMs: 15 * 60 * 1e3, maxIterations: 200, maxToolCalls: 600 },
8586
- "refactor-planner": { timeoutMs: 12 * 60 * 1e3, maxIterations: 180, maxToolCalls: 550 },
8587
- "security-scanner": { timeoutMs: 15 * 60 * 1e3, maxIterations: 200, maxToolCalls: 600 }
8612
+ "audit-log": { timeoutMs: 7.5 * 60 * 60 * 1e3, maxIterations: 5e3, maxToolCalls: 15e3 },
8613
+ "bug-hunter": { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 },
8614
+ "refactor-planner": { timeoutMs: 7.5 * 60 * 60 * 1e3, maxIterations: 6e3, maxToolCalls: 18e3 },
8615
+ "security-scanner": { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 }
8616
+ };
8617
+ var GENERIC_SUBAGENT_BUDGET = {
8618
+ timeoutMs: 3 * 60 * 60 * 1e3,
8619
+ maxIterations: 5e3,
8620
+ maxToolCalls: 15e3
8588
8621
  };
8589
8622
  function applyRosterBudget(cfg) {
8590
- const defaultBudget = FLEET_ROSTER_BUDGETS[cfg.role ?? ""];
8623
+ const roleBudget = cfg.role ? FLEET_ROSTER_BUDGETS[cfg.role] : void 0;
8624
+ const defaultBudget = roleBudget ?? (cfg.name ? GENERIC_SUBAGENT_BUDGET : void 0);
8591
8625
  if (!defaultBudget) return cfg;
8592
8626
  return {
8593
8627
  ...cfg,
@@ -8659,7 +8693,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
8659
8693
  // hasParentBridge() — the type now reflects this.
8660
8694
  parentBridge: null,
8661
8695
  doneCondition: this.config.doneCondition,
8662
- maxConcurrent: this.config.maxConcurrent ?? 4
8696
+ maxConcurrent: this.config.maxConcurrent ?? 16
8663
8697
  };
8664
8698
  this.subagents.set(id, {
8665
8699
  config: { ...subagent, id },
@@ -8786,7 +8820,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
8786
8820
  }
8787
8821
  }
8788
8822
  canDispatch() {
8789
- const max = this.config.maxConcurrent ?? 4;
8823
+ const max = this.config.maxConcurrent ?? 16;
8790
8824
  return this.inFlight < max && this.pendingTasks.length > 0;
8791
8825
  }
8792
8826
  takeNextDispatchableTask() {
@@ -8880,13 +8914,18 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
8880
8914
  task.subagentId = subagentId;
8881
8915
  subagent.context.tasks.push(task);
8882
8916
  this.emit("task.assigned", { task, subagentId });
8917
+ const rawMaxIterations = subagent.config.maxIterations;
8918
+ const rawMaxToolCalls = subagent.config.maxToolCalls;
8919
+ const rawMaxTokens = subagent.config.maxTokens;
8920
+ const rawMaxCostUsd = subagent.config.maxCostUsd;
8921
+ const rawTimeoutMs = subagent.config.timeoutMs;
8883
8922
  const configWithRosterDefaults = applyRosterBudget(subagent.config);
8884
8923
  const budget = new SubagentBudget({
8885
- maxIterations: configWithRosterDefaults.maxIterations ?? this.config.defaultBudget?.maxIterations,
8886
- maxToolCalls: task.maxToolCalls ?? configWithRosterDefaults.maxToolCalls ?? this.config.defaultBudget?.maxToolCalls,
8887
- maxTokens: configWithRosterDefaults.maxTokens ?? this.config.defaultBudget?.maxTokens,
8888
- maxCostUsd: configWithRosterDefaults.maxCostUsd ?? this.config.defaultBudget?.maxCostUsd,
8889
- timeoutMs: task.timeoutMs ?? configWithRosterDefaults.timeoutMs ?? this.config.defaultBudget?.timeoutMs
8924
+ maxIterations: rawMaxIterations ?? this.config.defaultBudget?.maxIterations ?? configWithRosterDefaults.maxIterations,
8925
+ maxToolCalls: rawMaxToolCalls ?? this.config.defaultBudget?.maxToolCalls ?? configWithRosterDefaults.maxToolCalls,
8926
+ maxTokens: rawMaxTokens ?? this.config.defaultBudget?.maxTokens ?? configWithRosterDefaults.maxTokens,
8927
+ maxCostUsd: rawMaxCostUsd ?? this.config.defaultBudget?.maxCostUsd ?? configWithRosterDefaults.maxCostUsd,
8928
+ timeoutMs: rawTimeoutMs ?? this.config.defaultBudget?.timeoutMs ?? configWithRosterDefaults.timeoutMs
8890
8929
  });
8891
8930
  subagent.activeBudget = budget;
8892
8931
  if (!this.runner) {
@@ -8957,7 +8996,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
8957
8996
  kind: "timeout",
8958
8997
  used: elapsed,
8959
8998
  limit,
8960
- timeoutMs: 3e4,
8999
+ timeoutMs: 6e4,
8961
9000
  extend: (extra) => resolveDecision({ extend: extra }),
8962
9001
  deny: () => resolveDecision("stop")
8963
9002
  });
@@ -10387,7 +10426,12 @@ var Director = class {
10387
10426
  }
10388
10427
  }
10389
10428
  }
10390
- const result = await this.coordinator.spawn(config);
10429
+ let result;
10430
+ try {
10431
+ result = await this.coordinator.spawn(config);
10432
+ } catch (err) {
10433
+ throw err;
10434
+ }
10391
10435
  if (this.fleetManager) {
10392
10436
  this.fleetManager.recordSpawn(result.subagentId, config, priceLookup);
10393
10437
  } else {
@@ -10835,7 +10879,7 @@ var Director = class {
10835
10879
  }
10836
10880
  };
10837
10881
  function createDelegateTool(opts) {
10838
- const defaultTimeoutMs = opts.defaultTimeoutMs ?? 4 * 60 * 60 * 1e3;
10882
+ const defaultTimeoutMs = opts.defaultTimeoutMs ?? 30 * 60 * 1e3;
10839
10883
  const rosterIds = opts.roster ? Object.keys(opts.roster) : [];
10840
10884
  const inputSchema = {
10841
10885
  type: "object",
@@ -10851,7 +10895,7 @@ function createDelegateTool(opts) {
10851
10895
  },
10852
10896
  name: {
10853
10897
  type: "string",
10854
- description: "Display name for the subagent when not using a roster role. Required when `role` is omitted."
10898
+ description: "Display name for free-form subagents (not using a roster role). The subagent gets a large default budget (3h, 5000 iter, 15000 tool calls). Required when `role` is omitted."
10855
10899
  },
10856
10900
  provider: {
10857
10901
  type: "string",
@@ -10882,8 +10926,8 @@ function createDelegateTool(opts) {
10882
10926
  };
10883
10927
  return {
10884
10928
  name: "delegate",
10885
- description: "Hand a discrete piece of work to a dedicated subagent and wait for its result. The subagent has its own context, its own LLM call, and its own budget \u2014 use this when a task is self-contained, would otherwise blow up your context, or benefits from a specialized role (bug-hunter, security-scanner, refactor-planner, audit-log). YOU decide how big the budget is: pass `timeoutMs`, `maxIterations`, and `maxToolCalls` sized to the actual work. There is no hidden cap forcing a 3-minute / 80-iteration limit \u2014 if a monorepo audit needs 2 hours and 500 tool calls, ask for that. Call multiple delegates in parallel through the provider's parallel-tool-call surface to fan work out across roles.",
10886
- usageHint: "Set `task` to a complete instruction. Either pick `role` from the roster or pass `name` + `provider` + `model`. For non-trivial work, also pass `timeoutMs` (the wall-clock budget you actually need), `maxIterations`, and `maxToolCalls` \u2014 defaults are intentionally generous (4 hours) but the right values depend on scope. Returns the subagent's `TaskResult` \u2014 including the textual `result`, iteration count, tool count, and duration. Auto-promotes the host into director mode on first call.",
10929
+ description: "Hand a discrete piece of work to a dedicated subagent and wait for its result. The subagent has its own context, its own LLM call, and its own budget \u2014 use this when a task is self-contained, would otherwise blow up your context, or benefits from a specialized role (bug-hunter, security-scanner, refactor-planner, audit-log). For free-form coding tasks (not tied to a pre-defined role), pass `name` + `task` \u2014 the subagent runs as a general-purpose coding agent with a large default budget. YOU decide how big the budget is: pass `timeoutMs`, `maxIterations`, and `maxToolCalls` sized to the actual work. There is no hidden cap forcing a 3-minute / 80-iteration limit \u2014 if a monorepo audit needs 2 hours and 500 tool calls, ask for that. Call multiple delegates in parallel through the provider's parallel-tool-call surface to fan work out across roles.",
10930
+ usageHint: "Set `task` to a complete instruction. Either pick `role` from the roster (audit-log, bug-hunter, refactor-planner, security-scanner) or pass `name` to run a free-form coding agent. For non-trivial work, also pass `timeoutMs`, `maxIterations`, and `maxToolCalls`. Returns the subagent's `TaskResult` \u2014 including the textual `result`, iteration count, tool count, and duration. Auto-promotes the host into director mode on first call.",
10887
10931
  permission: "auto",
10888
10932
  mutating: false,
10889
10933
  inputSchema,
@@ -10931,6 +10975,7 @@ function createDelegateTool(opts) {
10931
10975
  model: i.model,
10932
10976
  systemPromptOverride: i.systemPromptOverride
10933
10977
  };
10978
+ cfg = applyRosterBudget({ ...cfg, name: i.name });
10934
10979
  }
10935
10980
  if (typeof i.maxIterations === "number" && i.maxIterations > 0) {
10936
10981
  cfg.maxIterations = i.maxIterations;
@@ -10938,7 +10983,7 @@ function createDelegateTool(opts) {
10938
10983
  if (typeof i.maxToolCalls === "number" && i.maxToolCalls > 0) {
10939
10984
  cfg.maxToolCalls = i.maxToolCalls;
10940
10985
  }
10941
- const SUBAGENT_TIMEOUT_BUFFER_MS = opts.subagentTimeoutBufferMs ?? 3e4;
10986
+ const SUBAGENT_TIMEOUT_BUFFER_MS = opts.subagentTimeoutBufferMs ?? 6e4;
10942
10987
  const desiredSubTimeout = Math.max(3e4, timeoutMs - SUBAGENT_TIMEOUT_BUFFER_MS);
10943
10988
  if (!cfg.timeoutMs || cfg.timeoutMs > desiredSubTimeout) {
10944
10989
  cfg.timeoutMs = desiredSubTimeout;
@@ -10975,6 +11020,7 @@ function createDelegateTool(opts) {
10975
11020
  const errorKind = result.error?.kind;
10976
11021
  const retryable = result.error?.retryable;
10977
11022
  const backoffMs = result.error?.backoffMs;
11023
+ const summary = buildDelegateSummary(i.role, result);
10978
11024
  return {
10979
11025
  ok: result.status === "success",
10980
11026
  status: result.status,
@@ -10990,7 +11036,10 @@ function createDelegateTool(opts) {
10990
11036
  toolCalls: result.toolCalls,
10991
11037
  durationMs: result.durationMs,
10992
11038
  ...partial ? { partial } : {},
10993
- ...hintForKind(errorKind, retryable, backoffMs, partial) ? { hint: hintForKind(errorKind, retryable, backoffMs, partial) } : {}
11039
+ ...hintForKind(errorKind, retryable, backoffMs, partial) ? { hint: hintForKind(errorKind, retryable, backoffMs, partial) } : {},
11040
+ // Summary is included so callers (TUI, CLI renderer) can surface
11041
+ // it as a chat history line — the LLM also sees it for continuity.
11042
+ summary
10994
11043
  };
10995
11044
  } catch (err) {
10996
11045
  return {
@@ -11003,10 +11052,11 @@ function createDelegateTool(opts) {
11003
11052
  };
11004
11053
  }
11005
11054
  function instantiateRosterConfig2(role, base) {
11055
+ const withBudget = applyRosterBudget({ ...base, role });
11006
11056
  return {
11007
- ...base,
11008
- // Roster entries are templates. Give each spawn a fresh id so
11009
- // parallel or repeated delegates can use the same role safely.
11057
+ ...withBudget,
11058
+ // Give each spawn a fresh id so parallel or repeated delegates
11059
+ // can use the same role safely.
11010
11060
  id: `${role}-${randomUUID().slice(0, 8)}`
11011
11061
  };
11012
11062
  }
@@ -11066,6 +11116,18 @@ ${partial.lastAssistantText}`;
11066
11116
  return retryable ? "Failure classified as retryable. Try again with the same input." : void 0;
11067
11117
  }
11068
11118
  }
11119
+ function buildDelegateSummary(role, result) {
11120
+ const roleLabel = role ?? "subagent";
11121
+ const ms = result.durationMs;
11122
+ const duration = ms < 6e4 ? `${Math.round(ms / 1e3)}s` : ms < 36e5 ? `${Math.round(ms / 6e4)}m` : `${(ms / 36e5).toFixed(1)}h`;
11123
+ if (result.status === "success") {
11124
+ const preview = typeof result.result === "string" ? result.result.trim().slice(0, 120).replace(/\n+/g, " ") : null;
11125
+ const tail = preview ? ` \u2014 ${preview}` : "";
11126
+ return `[${roleLabel}] done in ${duration} (${result.iterations} iter, ${result.toolCalls} tools)${tail}`;
11127
+ }
11128
+ const errLabel = result.error?.kind ?? result.status;
11129
+ return `[${roleLabel}] ${result.status} after ${duration} (${result.iterations} iter, ${result.toolCalls} tools) \u2014 ${errLabel}`;
11130
+ }
11069
11131
  async function readSubagentPartial(opts, subagentId) {
11070
11132
  if (!opts.sessionsRoot) return void 0;
11071
11133
  const candidates = [];
@@ -17987,10 +18049,15 @@ var Agent = class {
17987
18049
  });
17988
18050
  let finalText = "";
17989
18051
  let iterations = 0;
18052
+ const delegateSummaries = [];
17990
18053
  let effectiveLimit = opts.maxIterations ?? this.maxIterations;
17991
18054
  const hasHardLimit = effectiveLimit > 0 && Number.isFinite(effectiveLimit);
17992
18055
  let recoveryRetries = 0;
17993
18056
  const autonomousContinue = opts.autonomousContinue ?? this.autonomousContinue;
18057
+ const onSubagentDone = ({ summary, ok }) => {
18058
+ delegateSummaries.push({ summary, ok });
18059
+ };
18060
+ const offSubagentDone = this.events.on("subagent.done", onSubagentDone);
17994
18061
  const diRunner = this.container.has(TOKENS.ProviderRunner) ? this.container.resolve(TOKENS.ProviderRunner) : null;
17995
18062
  const baseRunner = diRunner ? (ctx, req) => diRunner.run({
17996
18063
  provider: ctx.provider,
@@ -18012,116 +18079,122 @@ var Agent = class {
18012
18079
  tracer: this.tracer
18013
18080
  });
18014
18081
  const customRunner = this.extensions.wrapProviderRunner(baseRunner);
18015
- for (let i = 0; ; i++) {
18016
- iterations = i + 1;
18017
- if (controller.signal.aborted) {
18018
- return { status: "aborted", iterations };
18019
- }
18020
- if (autonomousContinue) {
18021
- consumeAutonomousContinue(this.ctx);
18022
- }
18023
- const limitCheck = await this.checkIterationLimit(
18024
- i,
18025
- effectiveLimit,
18026
- hasHardLimit,
18027
- iterations
18028
- );
18029
- effectiveLimit = limitCheck.limit;
18030
- if (limitCheck.exit) {
18031
- return { ...limitCheck.exit, finalText };
18032
- }
18033
- await this.extensions.runBeforeIteration(this.ctx, i);
18034
- this.events.emit("iteration.started", { ctx: this.ctx, index: i });
18035
- const req = await this.buildAndRunRequestPipeline(opts);
18036
- let res;
18037
- try {
18038
- res = await customRunner(this.ctx, req);
18039
- recoveryRetries = 0;
18040
- } catch (err) {
18082
+ try {
18083
+ for (let i = 0; ; i++) {
18084
+ iterations = i + 1;
18041
18085
  if (controller.signal.aborted) {
18042
- this.events.emit("error", { err: toError(err), phase: "provider" });
18043
- return { status: "aborted", iterations, error: toWrongStackError(err, "AGENT_ABORTED") };
18086
+ return { status: "aborted", iterations };
18044
18087
  }
18045
- const extDecision = await this.extensions.runOnError(this.ctx, err, "provider", i);
18046
- if (extDecision) {
18047
- if (extDecision.action === "fail") {
18088
+ if (autonomousContinue) {
18089
+ consumeAutonomousContinue(this.ctx);
18090
+ }
18091
+ const limitCheck = await this.checkIterationLimit(
18092
+ i,
18093
+ effectiveLimit,
18094
+ hasHardLimit,
18095
+ iterations,
18096
+ delegateSummaries
18097
+ );
18098
+ effectiveLimit = limitCheck.limit;
18099
+ if (limitCheck.exit) {
18100
+ return { ...limitCheck.exit, finalText };
18101
+ }
18102
+ await this.extensions.runBeforeIteration(this.ctx, i);
18103
+ this.events.emit("iteration.started", { ctx: this.ctx, index: i });
18104
+ const req = await this.buildAndRunRequestPipeline(opts);
18105
+ let res;
18106
+ try {
18107
+ res = await customRunner(this.ctx, req);
18108
+ recoveryRetries = 0;
18109
+ } catch (err) {
18110
+ if (controller.signal.aborted) {
18048
18111
  this.events.emit("error", { err: toError(err), phase: "provider" });
18049
- return { status: "failed", iterations, error: toWrongStackError(err) };
18112
+ return { status: "aborted", iterations, error: toWrongStackError(err, "AGENT_ABORTED") };
18050
18113
  }
18051
- if (extDecision.action === "continue") {
18052
- await this.extensions.runAfterIteration(this.ctx, i);
18053
- continue;
18114
+ const extDecision = await this.extensions.runOnError(this.ctx, err, "provider", i);
18115
+ if (extDecision) {
18116
+ if (extDecision.action === "fail") {
18117
+ this.events.emit("error", { err: toError(err), phase: "provider" });
18118
+ return { status: "failed", iterations, error: toWrongStackError(err), delegateSummaries };
18119
+ }
18120
+ if (extDecision.action === "continue") {
18121
+ await this.extensions.runAfterIteration(this.ctx, i);
18122
+ continue;
18123
+ }
18124
+ if (extDecision.action === "retry") {
18125
+ recoveryRetries++;
18126
+ if (recoveryRetries > 2) {
18127
+ this.events.emit("error", { err: toError(err), phase: "provider" });
18128
+ return { status: "failed", iterations, error: toWrongStackError(err), delegateSummaries };
18129
+ }
18130
+ if (extDecision.model) this.ctx.model = extDecision.model;
18131
+ this.logger.info("Extension requested retry; retrying turn");
18132
+ continue;
18133
+ }
18054
18134
  }
18055
- if (extDecision.action === "retry") {
18135
+ const recovered = await this.errorHandler.recover(err, this.ctx);
18136
+ if (!recovered || recovered.action === "fail") {
18137
+ this.events.emit("error", { err: toError(err), phase: "provider" });
18138
+ return {
18139
+ status: "failed",
18140
+ iterations,
18141
+ error: toWrongStackError(recovered?.error ?? err),
18142
+ delegateSummaries
18143
+ };
18144
+ }
18145
+ if (recovered.action === "retry") {
18056
18146
  recoveryRetries++;
18057
18147
  if (recoveryRetries > 2) {
18058
18148
  this.events.emit("error", { err: toError(err), phase: "provider" });
18059
18149
  return { status: "failed", iterations, error: toWrongStackError(err) };
18060
18150
  }
18061
- if (extDecision.model) this.ctx.model = extDecision.model;
18062
- this.logger.info("Extension requested retry; retrying turn");
18151
+ if (recovered.model) this.ctx.model = recovered.model;
18152
+ this.logger.info(`Recovered provider error via ${recovered.reason}; retrying turn`);
18063
18153
  continue;
18064
18154
  }
18155
+ recoveryRetries = 0;
18156
+ res = recovered.response;
18065
18157
  }
18066
- const recovered = await this.errorHandler.recover(err, this.ctx);
18067
- if (!recovered || recovered.action === "fail") {
18068
- this.events.emit("error", { err: toError(err), phase: "provider" });
18069
- return {
18070
- status: "failed",
18071
- iterations,
18072
- error: toWrongStackError(recovered?.error ?? err)
18073
- };
18158
+ const responseResult = await this.processResponse(res, req);
18159
+ if (responseResult.aborted) {
18160
+ return { status: "aborted", iterations, finalText: responseResult.finalText, delegateSummaries };
18074
18161
  }
18075
- if (recovered.action === "retry") {
18076
- recoveryRetries++;
18077
- if (recoveryRetries > 2) {
18078
- this.events.emit("error", { err: toError(err), phase: "provider" });
18079
- return { status: "failed", iterations, error: toWrongStackError(err) };
18162
+ if (responseResult.done) {
18163
+ return { status: "done", iterations, finalText: responseResult.finalText, delegateSummaries };
18164
+ }
18165
+ finalText = responseResult.finalText;
18166
+ const toolUses = res.content.filter(isToolUseBlock);
18167
+ if (toolUses.length === 0) {
18168
+ this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
18169
+ if (autonomousContinue && responseResult.directive === "continue") {
18170
+ await this.compactContextIfNeeded();
18171
+ await this.extensions.runAfterIteration(this.ctx, i);
18172
+ continue;
18080
18173
  }
18081
- if (recovered.model) this.ctx.model = recovered.model;
18082
- this.logger.info(`Recovered provider error via ${recovered.reason}; retrying turn`);
18083
- continue;
18174
+ if (autonomousContinue && responseResult.directive === "stop") {
18175
+ return { status: "done", iterations, finalText, delegateSummaries };
18176
+ }
18177
+ return { status: "done", iterations, finalText, delegateSummaries };
18084
18178
  }
18085
- recoveryRetries = 0;
18086
- res = recovered.response;
18087
- }
18088
- const responseResult = await this.processResponse(res, req);
18089
- if (responseResult.aborted) {
18090
- return { status: "aborted", iterations, finalText: responseResult.finalText };
18091
- }
18092
- if (responseResult.done) {
18093
- return { status: "done", iterations, finalText: responseResult.finalText };
18094
- }
18095
- finalText = responseResult.finalText;
18096
- const toolUses = res.content.filter(isToolUseBlock);
18097
- if (toolUses.length === 0) {
18098
- this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
18099
- if (autonomousContinue && responseResult.directive === "continue") {
18179
+ await this.executeTools(toolUses);
18180
+ if (autonomousContinue && consumeAutonomousContinue(this.ctx)) {
18181
+ this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
18100
18182
  await this.compactContextIfNeeded();
18101
18183
  await this.extensions.runAfterIteration(this.ctx, i);
18102
18184
  continue;
18103
18185
  }
18104
- if (autonomousContinue && responseResult.directive === "stop") {
18105
- return { status: "done", iterations, finalText };
18106
- }
18107
- return { status: "done", iterations, finalText };
18108
- }
18109
- await this.executeTools(toolUses);
18110
- if (autonomousContinue && consumeAutonomousContinue(this.ctx)) {
18111
18186
  this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
18112
18187
  await this.compactContextIfNeeded();
18113
18188
  await this.extensions.runAfterIteration(this.ctx, i);
18114
- continue;
18115
- }
18116
- this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
18117
- await this.compactContextIfNeeded();
18118
- await this.extensions.runAfterIteration(this.ctx, i);
18119
- if (autonomousContinue && responseResult.directive === "continue") {
18120
- continue;
18121
- }
18122
- if (autonomousContinue && responseResult.directive === "stop") {
18123
- return { status: "done", iterations, finalText };
18189
+ if (autonomousContinue && responseResult.directive === "continue") {
18190
+ continue;
18191
+ }
18192
+ if (autonomousContinue && responseResult.directive === "stop") {
18193
+ return { status: "done", iterations, finalText, delegateSummaries };
18194
+ }
18124
18195
  }
18196
+ } finally {
18197
+ offSubagentDone();
18125
18198
  }
18126
18199
  }
18127
18200
  /**
@@ -18130,7 +18203,7 @@ var Agent = class {
18130
18203
  * the loop should exit. Returns `{ limit }` with no result when the
18131
18204
  * iteration may proceed.
18132
18205
  */
18133
- async checkIterationLimit(iterationIndex, limit, hasHardLimit, currentIterations) {
18206
+ async checkIterationLimit(iterationIndex, limit, hasHardLimit, currentIterations, delegateSummaries) {
18134
18207
  if (hasHardLimit && iterationIndex >= limit) {
18135
18208
  const extendBy = await requestLimitExtension({
18136
18209
  events: this.events,
@@ -18143,7 +18216,7 @@ var Agent = class {
18143
18216
  this.logger.info(`Iteration limit extended by ${extendBy} (new limit: ${newLimit})`);
18144
18217
  return { limit: newLimit };
18145
18218
  }
18146
- return { limit, exit: { status: "max_iterations", iterations: currentIterations } };
18219
+ return { limit, exit: { status: "max_iterations", iterations: currentIterations, delegateSummaries } };
18147
18220
  }
18148
18221
  return { limit };
18149
18222
  }
@@ -18550,11 +18623,9 @@ var Context = class {
18550
18623
  return this._state;
18551
18624
  }
18552
18625
  /**
18553
- * Register a teardown hook tied to the current run's abort signal. The
18554
- * hook fires when the run aborts or ends normally Agent.run wires this
18555
- * through a RunController. Hooks registered before a run starts are stored
18556
- * and fired when the next run ends; there is no "immediate fire" when no
18557
- * run is active.
18626
+ * Register a teardown hook tied to the current run's abort signal.
18627
+ * Hooks registered before a run starts are stored and fired when the
18628
+ * next run ends; there is no immediate fire when no run is active.
18558
18629
  *
18559
18630
  * **Scope:** these hooks fire on the **whole agent run's** abort, not on
18560
18631
  * an individual tool call. For per-tool teardown of resources owned by
@@ -19133,7 +19204,7 @@ ${mem}`);
19133
19204
  };
19134
19205
 
19135
19206
  // src/registry/tool-registry.ts
19136
- var ToolRegistry = class {
19207
+ var ToolRegistry = class _ToolRegistry {
19137
19208
  tools = /* @__PURE__ */ new Map();
19138
19209
  register(tool, owner = "core") {
19139
19210
  if (this.tools.has(tool.name)) {
@@ -19255,6 +19326,15 @@ var ToolRegistry = class {
19255
19326
  clear() {
19256
19327
  this.tools.clear();
19257
19328
  }
19329
+ /**
19330
+ * Return a new ToolRegistry with the same registered tools and owners.
19331
+ * Useful for creating filtered copies in multi-agent scenarios.
19332
+ */
19333
+ clone() {
19334
+ const copy = new _ToolRegistry();
19335
+ for (const { tool, owner } of this.listWithOwner()) copy.register(tool, owner);
19336
+ return copy;
19337
+ }
19258
19338
  };
19259
19339
 
19260
19340
  // src/registry/provider-registry.ts
@@ -19714,7 +19794,12 @@ async function unloadPlugins(loadedPlugins, opts) {
19714
19794
  for (const plugin of ordered) {
19715
19795
  if (typeof plugin.teardown !== "function") continue;
19716
19796
  try {
19717
- const api = pluginApiMap.get(plugin) ?? opts.apiFactory(plugin);
19797
+ const api = pluginApiMap.get(plugin);
19798
+ if (!api) {
19799
+ throw new Error(
19800
+ `Plugin "${plugin.name}" API not found in pluginApiMap \u2014 was setup() called?`
19801
+ );
19802
+ }
19718
19803
  await plugin.teardown(api);
19719
19804
  pluginApiMap.delete(plugin);
19720
19805
  opts.log.info(`Plugin "${plugin.name}" torn down`);