@aexol/spectral 0.9.221 → 0.9.223

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 (166) hide show
  1. package/dist/agent/index.d.ts +20 -3
  2. package/dist/agent/index.d.ts.map +1 -1
  3. package/dist/agent/index.js +286 -80
  4. package/dist/extensions/aexol-backend-client.d.ts +85 -0
  5. package/dist/extensions/aexol-backend-client.d.ts.map +1 -0
  6. package/dist/extensions/aexol-backend-client.js +159 -0
  7. package/dist/extensions/aexol-mcp.d.ts +10 -6
  8. package/dist/extensions/aexol-mcp.d.ts.map +1 -1
  9. package/dist/extensions/aexol-mcp.js +21 -106
  10. package/dist/extensions/logic-trace-backend-draft.d.ts +68 -0
  11. package/dist/extensions/logic-trace-backend-draft.d.ts.map +1 -0
  12. package/dist/extensions/logic-trace-backend-draft.js +171 -0
  13. package/dist/extensions/logic-trace-validate.d.ts +33 -0
  14. package/dist/extensions/logic-trace-validate.d.ts.map +1 -0
  15. package/dist/extensions/logic-trace-validate.js +73 -0
  16. package/dist/extensions/logic-trace.d.ts +213 -0
  17. package/dist/extensions/logic-trace.d.ts.map +1 -0
  18. package/dist/extensions/logic-trace.js +1098 -0
  19. package/dist/generated/parser/lexer.d.ts +148 -0
  20. package/dist/generated/parser/lexer.d.ts.map +1 -0
  21. package/dist/generated/parser/lexer.js +877 -0
  22. package/dist/generated/parser/mod.d.ts +26 -0
  23. package/dist/generated/parser/mod.d.ts.map +1 -0
  24. package/dist/generated/parser/mod.js +30 -0
  25. package/dist/generated/parser/parser.d.ts +161 -0
  26. package/dist/generated/parser/parser.d.ts.map +1 -0
  27. package/dist/generated/parser/parser.js +754 -0
  28. package/dist/generated/parser/tokenizer.d.ts +107 -0
  29. package/dist/generated/parser/tokenizer.d.ts.map +1 -0
  30. package/dist/generated/parser/tokenizer.js +202 -0
  31. package/dist/generated/parser/validator.d.ts +45 -0
  32. package/dist/generated/parser/validator.d.ts.map +1 -0
  33. package/dist/generated/parser/validator.js +202 -0
  34. package/dist/generated/zeus/const.d.ts.map +1 -1
  35. package/dist/generated/zeus/const.js +4 -170
  36. package/dist/generated/zeus/index.d.ts +8 -873
  37. package/dist/generated/zeus/index.d.ts.map +1 -1
  38. package/dist/generated/zeus/index.js +0 -7
  39. package/dist/mcp/ui-stream-types.d.ts +2 -2
  40. package/dist/memory/tools/share-project-observation.js +1 -1
  41. package/dist/memory/tools/write-project-observation.d.ts.map +1 -1
  42. package/dist/memory/tools/write-project-observation.js +4 -3
  43. package/dist/sdk/agent-core/agent-loop.d.ts.map +1 -1
  44. package/dist/sdk/agent-core/agent-loop.js +2 -4
  45. package/dist/sdk/agent-core/harness/types.d.ts +0 -1
  46. package/dist/sdk/agent-core/harness/types.d.ts.map +1 -1
  47. package/dist/sdk/agent-core/index.d.ts +0 -8
  48. package/dist/sdk/agent-core/index.d.ts.map +1 -1
  49. package/dist/sdk/agent-core/index.js +0 -9
  50. package/dist/sdk/ai/index.d.ts +1 -0
  51. package/dist/sdk/ai/index.d.ts.map +1 -1
  52. package/dist/sdk/ai/index.js +1 -0
  53. package/dist/sdk/ai/utils/transient-error.d.ts +28 -0
  54. package/dist/sdk/ai/utils/transient-error.d.ts.map +1 -0
  55. package/dist/sdk/ai/utils/transient-error.js +55 -0
  56. package/dist/sdk/coding-agent/core/agent-session.d.ts.map +1 -1
  57. package/dist/sdk/coding-agent/core/agent-session.js +7 -3
  58. package/dist/sdk/coding-agent/core/extensions/index.d.ts +1 -1
  59. package/dist/sdk/coding-agent/core/extensions/index.d.ts.map +1 -1
  60. package/dist/sdk/coding-agent/core/extensions/native-extensions.js +2 -2
  61. package/dist/sdk/coding-agent/core/extensions/types.d.ts +20 -1
  62. package/dist/sdk/coding-agent/core/extensions/types.d.ts.map +1 -1
  63. package/dist/sdk/coding-agent/core/tools/tool-definition-wrapper.d.ts +9 -4
  64. package/dist/sdk/coding-agent/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  65. package/dist/sdk/coding-agent/core/tools/tool-definition-wrapper.js +15 -2
  66. package/dist/sdk/coding-agent/index.d.ts +1 -1
  67. package/dist/sdk/coding-agent/index.d.ts.map +1 -1
  68. package/dist/server/agent-bridge/headless-ui.d.ts +20 -0
  69. package/dist/server/agent-bridge/headless-ui.d.ts.map +1 -0
  70. package/dist/server/agent-bridge/headless-ui.js +85 -0
  71. package/dist/server/agent-bridge/pricing.d.ts +54 -0
  72. package/dist/server/agent-bridge/pricing.d.ts.map +1 -0
  73. package/dist/server/agent-bridge/pricing.js +226 -0
  74. package/dist/server/agent-bridge/rehydrate.d.ts +35 -0
  75. package/dist/server/agent-bridge/rehydrate.d.ts.map +1 -0
  76. package/dist/server/agent-bridge/rehydrate.js +122 -0
  77. package/dist/server/agent-bridge/synthetic-model.d.ts +27 -0
  78. package/dist/server/agent-bridge/synthetic-model.d.ts.map +1 -0
  79. package/dist/server/agent-bridge/synthetic-model.js +92 -0
  80. package/dist/server/agent-bridge.d.ts +17 -1
  81. package/dist/server/agent-bridge.d.ts.map +1 -1
  82. package/dist/server/agent-bridge.js +81 -496
  83. package/dist/server/error-humanizer.d.ts +11 -3
  84. package/dist/server/error-humanizer.d.ts.map +1 -1
  85. package/dist/server/error-humanizer.js +11 -3
  86. package/dist/server/session-stream/compaction-events.d.ts +13 -0
  87. package/dist/server/session-stream/compaction-events.d.ts.map +1 -0
  88. package/dist/server/session-stream/compaction-events.js +32 -0
  89. package/dist/server/session-stream/history-prune.d.ts +35 -0
  90. package/dist/server/session-stream/history-prune.d.ts.map +1 -0
  91. package/dist/server/session-stream/history-prune.js +182 -0
  92. package/dist/server/session-stream/memory.d.ts +48 -0
  93. package/dist/server/session-stream/memory.d.ts.map +1 -0
  94. package/dist/server/session-stream/memory.js +136 -0
  95. package/dist/server/session-stream/replay-tail.d.ts +4 -0
  96. package/dist/server/session-stream/replay-tail.d.ts.map +1 -0
  97. package/dist/server/session-stream/replay-tail.js +39 -0
  98. package/dist/server/session-stream/turn-events.d.ts +33 -0
  99. package/dist/server/session-stream/turn-events.d.ts.map +1 -0
  100. package/dist/server/session-stream/turn-events.js +65 -0
  101. package/dist/server/session-stream/turn-silence.d.ts +8 -0
  102. package/dist/server/session-stream/turn-silence.d.ts.map +1 -0
  103. package/dist/server/session-stream/turn-silence.js +72 -0
  104. package/dist/server/session-stream.d.ts +137 -36
  105. package/dist/server/session-stream.d.ts.map +1 -1
  106. package/dist/server/session-stream.js +18 -509
  107. package/dist/server/storage/observation-ranking.d.ts +14 -0
  108. package/dist/server/storage/observation-ranking.d.ts.map +1 -0
  109. package/dist/server/storage/observation-ranking.js +37 -0
  110. package/dist/server/storage/preflight.d.ts +20 -0
  111. package/dist/server/storage/preflight.d.ts.map +1 -0
  112. package/dist/server/storage/preflight.js +22 -0
  113. package/dist/server/storage/project-binding.d.ts +5 -0
  114. package/dist/server/storage/project-binding.d.ts.map +1 -0
  115. package/dist/server/storage/project-binding.js +32 -0
  116. package/dist/server/storage/rows.d.ts +104 -0
  117. package/dist/server/storage/rows.d.ts.map +1 -0
  118. package/dist/server/storage/rows.js +2 -0
  119. package/dist/server/storage/schema.d.ts +20 -0
  120. package/dist/server/storage/schema.d.ts.map +1 -0
  121. package/dist/server/storage/schema.js +134 -0
  122. package/dist/server/storage/types.d.ts +66 -0
  123. package/dist/server/storage/types.d.ts.map +1 -0
  124. package/dist/server/storage/types.js +1 -0
  125. package/dist/server/storage.d.ts +7 -94
  126. package/dist/server/storage.d.ts.map +1 -1
  127. package/dist/server/storage.js +6 -224
  128. package/dist/server/wire.d.ts +19 -0
  129. package/dist/server/wire.d.ts.map +1 -1
  130. package/package.json +2 -1
  131. package/dist/sdk/agent-core/harness/agent-harness.d.ts +0 -92
  132. package/dist/sdk/agent-core/harness/agent-harness.d.ts.map +0 -1
  133. package/dist/sdk/agent-core/harness/agent-harness.js +0 -899
  134. package/dist/sdk/agent-core/harness/env/nodejs.d.ts +0 -51
  135. package/dist/sdk/agent-core/harness/env/nodejs.d.ts.map +0 -1
  136. package/dist/sdk/agent-core/harness/env/nodejs.js +0 -485
  137. package/dist/sdk/agent-core/harness/prompt-templates.d.ts +0 -48
  138. package/dist/sdk/agent-core/harness/prompt-templates.d.ts.map +0 -1
  139. package/dist/sdk/agent-core/harness/prompt-templates.js +0 -229
  140. package/dist/sdk/agent-core/harness/session/jsonl-repo.d.ts +0 -26
  141. package/dist/sdk/agent-core/harness/session/jsonl-repo.d.ts.map +0 -1
  142. package/dist/sdk/agent-core/harness/session/jsonl-repo.js +0 -100
  143. package/dist/sdk/agent-core/harness/session/jsonl-storage.d.ts +0 -33
  144. package/dist/sdk/agent-core/harness/session/jsonl-storage.d.ts.map +0 -1
  145. package/dist/sdk/agent-core/harness/session/jsonl-storage.js +0 -230
  146. package/dist/sdk/agent-core/harness/session/memory-repo.d.ts +0 -18
  147. package/dist/sdk/agent-core/harness/session/memory-repo.d.ts.map +0 -1
  148. package/dist/sdk/agent-core/harness/session/memory-repo.js +0 -41
  149. package/dist/sdk/agent-core/harness/session/memory-storage.d.ts +0 -25
  150. package/dist/sdk/agent-core/harness/session/memory-storage.d.ts.map +0 -1
  151. package/dist/sdk/agent-core/harness/session/memory-storage.js +0 -113
  152. package/dist/sdk/agent-core/harness/session/repo-utils.d.ts +0 -11
  153. package/dist/sdk/agent-core/harness/session/repo-utils.d.ts.map +0 -1
  154. package/dist/sdk/agent-core/harness/session/repo-utils.js +0 -38
  155. package/dist/sdk/agent-core/harness/skills.d.ts +0 -44
  156. package/dist/sdk/agent-core/harness/skills.d.ts.map +0 -1
  157. package/dist/sdk/agent-core/harness/skills.js +0 -310
  158. package/dist/sdk/agent-core/harness/utils/shell-output.d.ts +0 -14
  159. package/dist/sdk/agent-core/harness/utils/shell-output.d.ts.map +0 -1
  160. package/dist/sdk/agent-core/harness/utils/shell-output.js +0 -125
  161. package/dist/sdk/agent-core/node.d.ts +0 -3
  162. package/dist/sdk/agent-core/node.d.ts.map +0 -1
  163. package/dist/sdk/agent-core/node.js +0 -2
  164. package/dist/sdk/agent-core/proxy.d.ts +0 -69
  165. package/dist/sdk/agent-core/proxy.d.ts.map +0 -1
  166. package/dist/sdk/agent-core/proxy.js +0 -297
@@ -22,13 +22,17 @@
22
22
  * - Tool filtering (only the tools specified in agent config)
23
23
  * - Model selection (session model preferred, agent-configured as fallback)
24
24
  * - Signal propagation (abort passthrough)
25
- * - Access to observational memory via the recall tool
25
+ * - Access to observational memory via the `recall` and
26
+ * `write_project_observation` tools, which run against a parent-session
27
+ * point-in-time snapshot (branch + session id); other observation tools
28
+ * (`share_project_observation`, `receive_agent_observations`,
29
+ * `compact_context`, `subagent`) remain excluded
26
30
  */
27
31
  import type { AgentTool } from "../sdk/agent-core/index.js";
28
32
  import { type ExtensionAPI, type ExtensionContext } from "../sdk/coding-agent/index.js";
29
33
  import { type AgentConfig } from "./agents.js";
30
34
  import type { ServerEvent } from "../server/wire.ts";
31
- import type { ExtensionContext as RichExtensionContext } from "../sdk/coding-agent/core/extensions/types.js";
35
+ import type { ReadonlySessionManager } from "../sdk/coding-agent/core/session-manager.js";
32
36
  /**
33
37
  * Build the system prompt for a subagent session.
34
38
  *
@@ -44,8 +48,21 @@ export declare function buildSubagentSystemPrompt(baseSystemPrompt: string | und
44
48
  * Give subagents a point-in-time branch view without exposing the live parent
45
49
  * SessionManager. Each getBranch call returns fresh clones of the snapshot.
46
50
  */
47
- export declare function createSubagentSessionManagerSnapshot(sessionManager: ExtensionContext["sessionManager"]): Pick<RichExtensionContext["sessionManager"], "getBranch">;
51
+ export declare function createSubagentSessionManagerSnapshot(sessionManager: ExtensionContext["sessionManager"]): Pick<ReadonlySessionManager, "getBranch" | "getSessionId">;
48
52
  export declare function resolveSubagentTools(cwd: string, ext: ExtensionAPI, ctx: ExtensionContext): AgentTool[];
53
+ /** Test hook: replace the run-level retry sleep (e.g. with an instant/collecting stub). */
54
+ export declare function setSubagentRetrySleepForTesting(fn?: (ms: number, signal?: AbortSignal) => Promise<void>): void;
55
+ /**
56
+ * Resolve the max number of child-run attempts for the run-level retry loop.
57
+ * An explicit tool param (clamped to 0-10) overrides everything — including a
58
+ * globally disabled retry switch. Without the param, the session default
59
+ * (3 retries) applies unless retry is explicitly disabled, in which case a
60
+ * single attempt is made.
61
+ */
62
+ export declare function resolveSubagentMaxAttempts(explicit: number | undefined, settings: {
63
+ enabled?: boolean;
64
+ maxRetries?: number;
65
+ } | undefined): number;
49
66
  export default function subagentExtension(ext: ExtensionAPI, opts?: {
50
67
  disabledAgents?: string[];
51
68
  emitSubagentEvent?: (event: ServerEvent) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAIX,SAAS,EAET,MAAM,4BAA4B,CAAC;AAUpC,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACN,KAAK,WAAW,EAKhB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAQrD,OAAO,KAAK,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AAuG7G;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACxC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC,GACpF,MAAM,CAYR;AA0JD;;;GAGG;AACH,wBAAgB,oCAAoC,CACnD,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAChD,IAAI,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,CAK3D;AAoBD,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,YAAY,EACjB,GAAG,EAAE,gBAAgB,GACnB,SAAS,EAAE,CAoCb;AAycD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACxC,GAAG,EAAE,YAAY,EACjB,IAAI,CAAC,EAAE;IACN,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB,GACC,IAAI,CAgaN"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAIX,SAAS,EAET,MAAM,4BAA4B,CAAC;AAqBpC,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAErB,MAAM,8BAA8B,CAAC;AAItC,OAAO,EACN,KAAK,WAAW,EAKhB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAQrD,OAAO,KAAK,EAAE,sBAAsB,EAAgB,MAAM,6CAA6C,CAAC;AAuGxG;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACxC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC,GACpF,MAAM,CAYR;AA4JD;;;GAGG;AACH,wBAAgB,oCAAoC,CACnD,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAChD,IAAI,CAAC,sBAAsB,EAAE,WAAW,GAAG,cAAc,CAAC,CAe5D;AA6BD,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,YAAY,EACjB,GAAG,EAAE,gBAAgB,GACnB,SAAS,EAAE,CAwCb;AAqHD,2FAA2F;AAC3F,wBAAgB,+BAA+B,CAC9C,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GACtD,IAAI,CAEN;AAmBD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAC9D,MAAM,CAiBR;AA2eD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACxC,GAAG,EAAE,YAAY,EACjB,IAAI,CAAC,EAAE;IACN,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB,GACC,IAAI,CA2aN"}
@@ -22,12 +22,17 @@
22
22
  * - Tool filtering (only the tools specified in agent config)
23
23
  * - Model selection (session model preferred, agent-configured as fallback)
24
24
  * - Signal propagation (abort passthrough)
25
- * - Access to observational memory via the recall tool
25
+ * - Access to observational memory via the `recall` and
26
+ * `write_project_observation` tools, which run against a parent-session
27
+ * point-in-time snapshot (branch + session id); other observation tools
28
+ * (`share_project_observation`, `receive_agent_observations`,
29
+ * `compact_context`, `subagent`) remain excluded
26
30
  */
27
- import { agentLoop } from "../sdk/agent-core/index.js";
31
+ import { agentLoop, agentLoopContinue, } from "../sdk/agent-core/index.js";
28
32
  import { buildIsolatedRequestTimePrunedMessagesResult, COMPACT_CONTEXT_TOOL_NAME, } from "../memory/tools/compact-context.js";
29
- import { StringEnum } from "../sdk/ai/index.js";
33
+ import { isRateLimitError, isTransientApiError, isContextOverflow, isPaymentRequiredError, StringEnum, streamSimple, } from "../sdk/ai/index.js";
30
34
  import { mutateSystemPrompt } from "../sdk/coding-agent/core/system-prompt-mutator.js";
35
+ import { sleep } from "../sdk/coding-agent/utils/sleep.js";
31
36
  import { Type } from "typebox";
32
37
  import { discoverAgents, agentMetadataBlock, } from "./agents.js";
33
38
  import { loadAgentSettings } from "../server/handlers/agent-settings.js";
@@ -40,6 +45,7 @@ import { wrapToolDefinition } from "../sdk/coding-agent/core/tools/tool-definiti
40
45
  import { RECALL_OBSERVATION_TOOL_NAME } from "../memory/tools/recall-observation.js";
41
46
  import { RECEIVE_AGENT_OBSERVATIONS_TOOL_NAME } from "../memory/tools/receive-agent-observations.js";
42
47
  import { SHARE_PROJECT_OBSERVATION_TOOL_NAME } from "../memory/tools/share-project-observation.js";
48
+ import { WRITE_PROJECT_OBSERVATION_TOOL_NAME } from "../memory/tools/write-project-observation.js";
43
49
  import { compressSubagentToolResult } from "../memory/tool-output-compressor.js";
44
50
  // ---------------------------------------------------------------------------
45
51
  // Constants
@@ -230,8 +236,18 @@ function cloneSessionEntry(entry) {
230
236
  */
231
237
  export function createSubagentSessionManagerSnapshot(sessionManager) {
232
238
  const snapshot = sessionManager.getBranch().map(cloneSessionEntry);
239
+ // Optional call tolerates minimal branch-only snapshots in tests; a
240
+ // missing id falls through to the tools' `no_session` handling.
241
+ const sessionId = sessionManager.getSessionId?.();
233
242
  return {
234
243
  getBranch: () => snapshot.map(cloneSessionEntry),
244
+ // Captured eagerly so the session id and the branch snapshot come
245
+ // from the same point in time. fork/newSession mutate the live
246
+ // SessionManager's sessionId in place, so a lazy read could diverge
247
+ // from the point-in-time branch on a mid-run fork. Subagent
248
+ // observations must be attributed to the parent session id at
249
+ // snapshot creation, same branch semantics as `recall`.
250
+ getSessionId: () => sessionId,
235
251
  };
236
252
  }
237
253
  /**
@@ -251,14 +267,27 @@ const SUBAGENT_EXCLUDED_TOOL_NAMES = new Set([
251
267
  RECEIVE_AGENT_OBSERVATIONS_TOOL_NAME,
252
268
  SHARE_PROJECT_OBSERVATION_TOOL_NAME,
253
269
  ]);
270
+ /**
271
+ * Extension tools that run with the parent session's point-in-time branch
272
+ * snapshot instead of the bare `{ cwd, getSystemPrompt }` isolated context.
273
+ */
274
+ const SUBAGENT_SESSION_SNAPSHOT_TOOL_NAMES = new Set([
275
+ RECALL_OBSERVATION_TOOL_NAME,
276
+ WRITE_PROJECT_OBSERVATION_TOOL_NAME,
277
+ ]);
254
278
  export function resolveSubagentTools(cwd, ext, ctx) {
255
279
  // Subagents receive every tool registered on the primary agent. Built-in
256
280
  // tools are created fresh with the subagent's isolated cwd/jobs, and
257
- // extension-registered tools are wrapped with an isolated context exposing
258
- // only `cwd` and `getSystemPrompt` (plus a read-only branch snapshot for
259
- // `recall`).
281
+ // extension-registered tools are wrapped with a `SubagentToolContext`:
282
+ // always `cwd` + `getSystemPrompt`, plus a point-in-time parent-session
283
+ // branch snapshot for the observation tools that need branch/session
284
+ // semantics. Everything else (ui, modelRegistry, live sessionManager) is
285
+ // absent at runtime, so handlers must guard those members.
260
286
  const tools = [];
261
287
  const jobs = new BashJobRegistry();
288
+ // One shared snapshot per invocation so all snapshot-routed tools observe
289
+ // the same parent-session epoch (branch + session id).
290
+ const sharedSnapshot = createSubagentSessionManagerSnapshot(ctx.sessionManager);
262
291
  for (const toolInfo of ext.getAllTools()) {
263
292
  const name = toolInfo.name;
264
293
  if (SUBAGENT_EXCLUDED_TOOL_NAMES.has(name))
@@ -278,11 +307,10 @@ export function resolveSubagentTools(cwd, ext, ctx) {
278
307
  const toolDef = ext.getToolDefinition(name);
279
308
  if (!toolDef)
280
309
  continue;
281
- const isolatedContext = name === RECALL_OBSERVATION_TOOL_NAME
282
- ? { cwd, sessionManager: createSubagentSessionManagerSnapshot(ctx.sessionManager), getSystemPrompt: ctx.getSystemPrompt }
310
+ const isolatedContext = SUBAGENT_SESSION_SNAPSHOT_TOOL_NAMES.has(name)
311
+ ? { cwd, sessionManager: sharedSnapshot, getSystemPrompt: ctx.getSystemPrompt }
283
312
  : { cwd, getSystemPrompt: ctx.getSystemPrompt };
284
- const isolatedContextWithNoParent = isolatedContext;
285
- tools.push(wrapToolDefinition(toolDef, () => isolatedContextWithNoParent));
313
+ tools.push(wrapToolDefinition(toolDef, () => isolatedContext));
286
314
  }
287
315
  return tools;
288
316
  }
@@ -307,15 +335,17 @@ async function mapWithConcurrencyLimit(items, concurrency, fn) {
307
335
  return results;
308
336
  }
309
337
  /**
310
- * Wraps `runSingleAgent` with an independent per-subagent timeout.
338
+ * Runs a child agent with an independent per-subagent timeout.
311
339
  *
312
340
  * Combines the parent's abort signal with a fresh timeout AbortController so
313
341
  * that no single subagent can exhaust the parent prompt's full timeout budget.
342
+ * The budget covers the WHOLE child run including any resume retries (see
343
+ * `runSingleAgent`), so wall time stays bounded by SUBAGENT_TIMEOUT_MS.
314
344
  * On timeout, returns a clear error result instead of throwing so the parent
315
345
  * agent can continue (e.g. stop a chain, or surface the error as the tool
316
346
  * result for parallel/single modes).
317
347
  */
318
- async function runSingleAgentWithTimeout(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, parentToolCallId, onInternalEvent, ext, ctx) {
348
+ async function runSingleAgentWithTimeout(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, parentToolCallId, onInternalEvent, ext, ctx, maxRetries) {
319
349
  const timeoutMs = SUBAGENT_TIMEOUT_MS;
320
350
  const timeoutSeconds = timeoutMs / 1000;
321
351
  const controller = new AbortController();
@@ -329,7 +359,7 @@ async function runSingleAgentWithTimeout(defaultCwd, agents, agentName, task, cw
329
359
  signal.addEventListener("abort", onParentAbort, { once: true });
330
360
  }
331
361
  try {
332
- const result = await runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, controller.signal, onUpdate, makeDetails, parentToolCallId, onInternalEvent, ext, ctx);
362
+ const result = await runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, controller.signal, onUpdate, makeDetails, parentToolCallId, onInternalEvent, ext, ctx, maxRetries);
333
363
  // If the timeout fired (and parent signal did not), surface a clean
334
364
  // timeout error result rather than a bare "aborted" result.
335
365
  if (controller.signal.aborted &&
@@ -352,10 +382,61 @@ async function runSingleAgentWithTimeout(defaultCwd, agents, agentName, task, cw
352
382
  clearTimeout(timeoutId);
353
383
  }
354
384
  }
385
+ /**
386
+ * Backoff sleep for the run-level retry loop; overridable in tests. Abort-aware
387
+ * (mirrors the main session's abortable retry sleep): it rejects as soon as the
388
+ * run signal aborts instead of stalling for the full delay.
389
+ */
390
+ let retrySleep = (ms, signal) => sleep(ms, signal);
391
+ /** Test hook: replace the run-level retry sleep (e.g. with an instant/collecting stub). */
392
+ export function setSubagentRetrySleepForTesting(fn) {
393
+ retrySleep = fn ?? ((ms, signal) => sleep(ms, signal));
394
+ }
395
+ /** Upper bound for the tool-level `maxRetries` param (defense against bad values). */
396
+ const SUBAGENT_MAX_RETRIES_CAP = 10;
397
+ /**
398
+ * Minimal assistant-shaped probe used to ask `isContextOverflow` about a bare
399
+ * error string during retry classification.
400
+ */
401
+ function buildOverflowProbe(errorMessage) {
402
+ return {
403
+ role: "assistant",
404
+ content: [],
405
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
406
+ stopReason: "error",
407
+ errorMessage,
408
+ };
409
+ }
410
+ /**
411
+ * Resolve the max number of child-run attempts for the run-level retry loop.
412
+ * An explicit tool param (clamped to 0-10) overrides everything — including a
413
+ * globally disabled retry switch. Without the param, the session default
414
+ * (3 retries) applies unless retry is explicitly disabled, in which case a
415
+ * single attempt is made.
416
+ */
417
+ export function resolveSubagentMaxAttempts(explicit, settings) {
418
+ // Non-finite values (NaN/Infinity) from direct internal callers are treated
419
+ // as absent — otherwise `1 + NaN` would poison the attempts cap and loop.
420
+ const capped = explicit !== undefined && Number.isFinite(explicit)
421
+ ? Math.max(0, Math.min(SUBAGENT_MAX_RETRIES_CAP, Math.floor(explicit)))
422
+ : undefined;
423
+ if (capped !== undefined)
424
+ return 1 + capped;
425
+ if (settings && settings.enabled === false)
426
+ return 1;
427
+ // Settings-derived values are hardened the same way as the explicit param:
428
+ // a non-finite maxRetries would otherwise poison the cap (`segments >= NaN`
429
+ // is never true → unbounded retries).
430
+ const settingsRetries = Number.isFinite(settings?.maxRetries)
431
+ ? Math.min(SUBAGENT_MAX_RETRIES_CAP, settings.maxRetries)
432
+ : undefined;
433
+ const retries = settingsRetries ?? 3;
434
+ return 1 + retries;
435
+ }
355
436
  // ---------------------------------------------------------------------------
356
437
  // Core — run a single subagent in-process via agentLoop
357
438
  // ---------------------------------------------------------------------------
358
- async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, parentToolCallId, onInternalEvent, ext, ctx) {
439
+ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, parentToolCallId, onInternalEvent, ext, ctx, maxRetries) {
359
440
  const normalizedAgentName = agentName.replace(/^@/, "");
360
441
  const agent = agents.find((a) => a.name === normalizedAgentName);
361
442
  if (!agent) {
@@ -466,7 +547,29 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, si
466
547
  });
467
548
  }
468
549
  };
550
+ // Run-level retry policy for the resume loop below (mirrors
551
+ // AgentSession._prepareRetry + its settings-driven backoff).
552
+ const retrySettings = ctx.settingsManager?.getRetrySettings?.();
553
+ const maxSegments = resolveSubagentMaxAttempts(maxRetries, retrySettings);
554
+ const baseDelayMs = Number.isFinite(retrySettings?.baseDelayMs)
555
+ ? retrySettings?.baseDelayMs
556
+ : 2000;
469
557
  try {
558
+ // Provider retry settings: subagents must inherit the same configurable
559
+ // retry policy as the main session (see sdk.ts streamFn wrapper) instead
560
+ // of silently falling back to provider SDK defaults (e.g. OpenAI's
561
+ // maxRetries=2 is too few for multi-minute outages). `ctx.settingsManager`
562
+ // is optional on ExtensionContext — when absent the wrapper below simply
563
+ // forwards options untouched, so provider/SDK defaults still apply.
564
+ // Optional call: symmetric with getRetrySettings?.() above — partial
565
+ // settingsManager stubs (extension contexts, tests) must not throw.
566
+ const providerRetrySettings = ctx.settingsManager?.getProviderRetrySettings?.();
567
+ const subagentStreamFn = (streamModel, streamContext, options) => streamSimple(streamModel, streamContext, {
568
+ ...options,
569
+ timeoutMs: options?.timeoutMs ?? providerRetrySettings?.timeoutMs,
570
+ maxRetries: options?.maxRetries ?? providerRetrySettings?.maxRetries,
571
+ maxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings?.maxRetryDelayMs,
572
+ });
470
573
  // Invocation-local hook state; never reuse the parent extension context/runtime.
471
574
  const config = {
472
575
  model,
@@ -496,81 +599,166 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, si
496
599
  }
497
600
  },
498
601
  };
499
- const stream = agentLoop([{ role: "user", content: [{ type: "text", text: task }], timestamp: Date.now() }], {
602
+ const initialPrompt = [
603
+ {
604
+ role: "user",
605
+ content: [{ type: "text", text: task }],
606
+ timestamp: Date.now(),
607
+ },
608
+ ];
609
+ const baseContext = {
500
610
  systemPrompt: `${effectivePrompt}\n\n---\n\n# Task\n\n${task}`,
501
611
  messages: [],
502
612
  tools,
503
- }, config, signal);
613
+ };
504
614
  // Collect messages from the stream
505
615
  const collectedMessages = [];
506
616
  let hadError = false;
507
- for await (const event of stream) {
508
- if (signal?.aborted) {
509
- hadError = true;
510
- break;
511
- }
512
- onInternalEvent?.(event, parentToolCallId);
513
- if (event.type === "message_update" && event.message?.role === "assistant") {
514
- // Forward streaming text/thinking deltas so the UI can show the
515
- // subagent process as it's generated, not just the final result.
516
- const inner = event.assistantMessageEvent;
517
- if (inner?.type === "text_delta" && inner.delta) {
518
- streamingText += inner.delta;
519
- emitUpdate();
617
+ let segments = 0;
618
+ // One child run may span several segments: the first one starts the
619
+ // loop, any later one resumes it. Tool results already recorded in
620
+ // `collectedMessages` are part of the resumed context, so tools are
621
+ // never re-executed by a retry.
622
+ const consumeStream = async (stream) => {
623
+ for await (const event of stream) {
624
+ if (signal?.aborted) {
625
+ hadError = true;
626
+ break;
520
627
  }
521
- else if (inner?.type === "thinking_delta" && inner.delta) {
522
- thinkingText += inner.delta;
523
- if (inner.metadata) {
524
- thinkingMetadata = { ...(thinkingMetadata ?? {}), ...inner.metadata };
628
+ onInternalEvent?.(event, parentToolCallId);
629
+ if (event.type === "message_update" && event.message?.role === "assistant") {
630
+ // Forward streaming text/thinking deltas so the UI can show the
631
+ // subagent process as it's generated, not just the final result.
632
+ const inner = event.assistantMessageEvent;
633
+ if (inner?.type === "text_delta" && inner.delta) {
634
+ streamingText += inner.delta;
635
+ emitUpdate();
525
636
  }
526
- emitUpdate();
527
- }
528
- continue;
529
- }
530
- if (event.type === "message_end" && event.message) {
531
- const msg = event.message;
532
- collectedMessages.push(msg);
533
- if (msg.role === "assistant") {
534
- // Reset streaming accumulator — final text is now in messages
535
- streamingText = "";
536
- currentResult.usage.turns++;
537
- const usage = msg.usage;
538
- if (usage) {
539
- currentResult.usage.input += usage.input || 0;
540
- currentResult.usage.output += usage.output || 0;
541
- currentResult.usage.cacheRead += usage.cacheRead || 0;
542
- currentResult.usage.cacheWrite += usage.cacheWrite || 0;
543
- currentResult.usage.cost += usage.cost?.total || 0;
544
- currentResult.usage.contextTokens = usage.totalTokens || 0;
637
+ else if (inner?.type === "thinking_delta" && inner.delta) {
638
+ thinkingText += inner.delta;
639
+ if (inner.metadata) {
640
+ thinkingMetadata = { ...(thinkingMetadata ?? {}), ...inner.metadata };
641
+ }
642
+ emitUpdate();
545
643
  }
546
- if (!currentResult.model && msg.model)
547
- currentResult.model = msg.model;
548
- if (msg.stopReason)
549
- currentResult.stopReason = msg.stopReason;
550
- if (msg.errorMessage)
551
- currentResult.errorMessage = msg.errorMessage;
552
- if (msg.stopReason === "error" || msg.stopReason === "aborted") {
553
- hadError = true;
644
+ continue;
645
+ }
646
+ if (event.type === "message_end" && event.message) {
647
+ const msg = event.message;
648
+ collectedMessages.push(msg);
649
+ if (msg.role === "assistant") {
650
+ // Reset streaming accumulator final text is now in messages
651
+ streamingText = "";
652
+ currentResult.usage.turns++;
653
+ const usage = msg.usage;
654
+ if (usage) {
655
+ currentResult.usage.input += usage.input || 0;
656
+ currentResult.usage.output += usage.output || 0;
657
+ currentResult.usage.cacheRead += usage.cacheRead || 0;
658
+ currentResult.usage.cacheWrite += usage.cacheWrite || 0;
659
+ currentResult.usage.cost += usage.cost?.total || 0;
660
+ currentResult.usage.contextTokens = usage.totalTokens || 0;
661
+ }
662
+ if (!currentResult.model && msg.model)
663
+ currentResult.model = msg.model;
664
+ if (msg.stopReason)
665
+ currentResult.stopReason = msg.stopReason;
666
+ if (msg.errorMessage)
667
+ currentResult.errorMessage = msg.errorMessage;
668
+ if (msg.stopReason === "error" || msg.stopReason === "aborted") {
669
+ hadError = true;
670
+ }
554
671
  }
672
+ currentResult.messages = [...collectedMessages];
673
+ emitUpdate();
674
+ }
675
+ if (event.type === "tool_execution_end" && event.isError) {
676
+ emitUpdate();
677
+ }
678
+ if (event.type === "agent_end" && event.error) {
679
+ hadError = true;
680
+ currentResult.errorMessage = event.error;
681
+ currentResult.stderr = event.error;
555
682
  }
556
- currentResult.messages = [...collectedMessages];
557
- emitUpdate();
558
683
  }
559
- if (event.type === "tool_execution_end" && event.isError) {
560
- emitUpdate();
684
+ };
685
+ for (;;) {
686
+ segments++;
687
+ // Per-segment transient state: a resumed segment must be able to
688
+ // succeed without inheriting the previous segment's failure flags.
689
+ hadError = false;
690
+ streamingText = "";
691
+ // Drop thinking accumulated by the failed segment so the live sheet
692
+ // shows the resumed segment's reasoning, not stale text.
693
+ thinkingText = "";
694
+ thinkingMetadata = undefined;
695
+ currentResult.stopReason = undefined;
696
+ currentResult.errorMessage = undefined;
697
+ currentResult.stderr = "";
698
+ // Resume (segments > 1) continues the child with its existing
699
+ // transcript through `agentLoopContinue` — the same mechanism the
700
+ // main session uses (Agent.continue → runAgentLoopContinue) — so
701
+ // already-executed tools are NOT re-run. Only when there is nothing
702
+ // to resume from (empty transcript) do we fall back to a fresh
703
+ // `agentLoop` call, which then re-emits the initial prompt.
704
+ const canResume = collectedMessages.length > 0 &&
705
+ collectedMessages[collectedMessages.length - 1].role !== "assistant";
706
+ const stream = segments === 1 || !canResume
707
+ ? agentLoop(initialPrompt, baseContext, config, signal, subagentStreamFn)
708
+ : agentLoopContinue({ ...baseContext, messages: [...collectedMessages] }, config, signal, subagentStreamFn);
709
+ await consumeStream(stream);
710
+ // Drain the stream result (already consumed by iteration, but ensure cleanup)
711
+ try {
712
+ await stream.result();
561
713
  }
562
- if (event.type === "agent_end" && event.error) {
563
- hadError = true;
564
- currentResult.errorMessage = event.error;
565
- currentResult.stderr = event.error;
714
+ catch {
715
+ // Stream result error — already handled by message events
566
716
  }
567
- }
568
- // Drain the stream result (already consumed by iteration, but ensure cleanup)
569
- try {
570
- await stream.result();
571
- }
572
- catch {
573
- // Stream result error already handled by message events
717
+ // ── Run-level retry decision (mirrors AgentSession._prepareRetry) ──
718
+ if (segments >= maxSegments)
719
+ break;
720
+ if (currentResult.stopReason !== "error")
721
+ break;
722
+ // Abort after a completed segment (parent stop or budget timeout):
723
+ // never retry, and never sleep into a phantom extra segment.
724
+ if (signal?.aborted)
725
+ break;
726
+ const errorMessage = currentResult.errorMessage || "";
727
+ // Payment required (402) is a billing problem — retries cannot help.
728
+ // Explicit for parity with AgentSession._isRetryableError.
729
+ if (isPaymentRequiredError(errorMessage))
730
+ break;
731
+ // Context overflow is a hard failure, not transient. It must be
732
+ // checked before the classifiers because overflow messages can
733
+ // contain bare status-code-like numerals (e.g. "501234 tokens >
734
+ // 500000 maximum").
735
+ if (isContextOverflow(buildOverflowProbe(errorMessage), model.contextWindow)) {
736
+ break;
737
+ }
738
+ if (!isRateLimitError(errorMessage) && !isTransientApiError(errorMessage)) {
739
+ break;
740
+ }
741
+ // Drop the failed assistant message(s) so the child resumes AT the
742
+ // failed turn instead of re-running it. Several trailing assistant
743
+ // messages are possible: the in-loop retry emits a failed assistant
744
+ // message before popping it from the loop context.
745
+ while (collectedMessages.length > 0 &&
746
+ collectedMessages[collectedMessages.length - 1].role === "assistant") {
747
+ collectedMessages.pop();
748
+ }
749
+ currentResult.messages = [...collectedMessages];
750
+ try {
751
+ await retrySleep(baseDelayMs * 2 ** (segments - 1), signal);
752
+ }
753
+ catch {
754
+ // Aborted during the backoff window (the sleep rejects on abort):
755
+ // fall through to the check below instead of throwing out of the
756
+ // child run.
757
+ }
758
+ // Abort during the backoff window: break so the attempt annotation
759
+ // counts only completed segments.
760
+ if (signal?.aborted)
761
+ break;
574
762
  }
575
763
  currentResult.exitCode = hadError ? 1 : 0;
576
764
  if (signal?.aborted) {
@@ -578,6 +766,12 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, si
578
766
  currentResult.stopReason = "aborted";
579
767
  currentResult.errorMessage = "Subagent was aborted";
580
768
  }
769
+ if (segments > 1) {
770
+ currentResult.attempts = segments;
771
+ if (currentResult.exitCode !== 0 && currentResult.errorMessage) {
772
+ currentResult.errorMessage = `${currentResult.errorMessage} (failed after ${segments} attempts)`;
773
+ }
774
+ }
581
775
  return currentResult;
582
776
  }
583
777
  catch (err) {
@@ -625,6 +819,11 @@ const SubagentParams = Type.Object({
625
819
  cwd: Type.Optional(Type.String({
626
820
  description: "Working directory for the agent process (single mode)",
627
821
  })),
822
+ maxRetries: Type.Optional(Type.Integer({
823
+ description: "Max automatic resume retries after a transient provider failure: the child resumes at the failed turn instead of restarting, so its tools are not re-executed (overrides the configured retry count and a disabled retry switch; 0-10).",
824
+ minimum: 0,
825
+ maximum: 10,
826
+ })),
628
827
  });
629
828
  // ---------------------------------------------------------------------------
630
829
  // Extension entry point
@@ -807,7 +1006,7 @@ export default function subagentExtension(ext, opts) {
807
1006
  }
808
1007
  }
809
1008
  : undefined;
810
- const result = await runSingleAgentWithTimeout(ctx.cwd, agents, step.agent, taskWithContext, step.cwd, i + 1, signal, chainUpdate, makeDetails("chain"), _toolCallId, emitSubagentToolProgress, ext, ctx);
1009
+ const result = await runSingleAgentWithTimeout(ctx.cwd, agents, step.agent, taskWithContext, step.cwd, i + 1, signal, chainUpdate, makeDetails("chain"), _toolCallId, emitSubagentToolProgress, ext, ctx, params.maxRetries);
811
1010
  results.push(result);
812
1011
  const isError = result.exitCode !== 0 ||
813
1012
  result.stopReason === "error" ||
@@ -834,7 +1033,9 @@ export default function subagentExtension(ext, opts) {
834
1033
  const output = truncateOutput(getFinalOutput(r.messages) || "(no output)", SUBAGENT_OUTPUT_LIMIT);
835
1034
  const status = r.exitCode === 0
836
1035
  ? "completed"
837
- : "failed";
1036
+ : r.attempts && r.attempts > 1
1037
+ ? `failed (after ${r.attempts} attempts)`
1038
+ : "failed";
838
1039
  return `[step ${idx + 1} - ${r.agent}] ${status}:\n${output}`;
839
1040
  });
840
1041
  return {
@@ -892,7 +1093,7 @@ export default function subagentExtension(ext, opts) {
892
1093
  allResults[index] = partial.details.results[0];
893
1094
  emitParallelUpdate();
894
1095
  }
895
- }, makeDetails("parallel"), _toolCallId, emitSubagentToolProgress, ext, ctx);
1096
+ }, makeDetails("parallel"), _toolCallId, emitSubagentToolProgress, ext, ctx, params.maxRetries);
896
1097
  allResults[index] = result;
897
1098
  emitParallelUpdate();
898
1099
  return result;
@@ -900,7 +1101,12 @@ export default function subagentExtension(ext, opts) {
900
1101
  const successCount = results.filter((r) => r.exitCode === 0).length;
901
1102
  const summaries = results.map((r) => {
902
1103
  const output = truncateOutput(getFinalOutput(r.messages), SUBAGENT_OUTPUT_LIMIT);
903
- return `[${r.agent}] ${r.exitCode === 0 ? "completed" : "failed"}:\n${output || "(no output)"}`;
1104
+ const status = r.exitCode === 0
1105
+ ? "completed"
1106
+ : r.attempts && r.attempts > 1
1107
+ ? `failed (after ${r.attempts} attempts)`
1108
+ : "failed";
1109
+ return `[${r.agent}] ${status}:\n${output || "(no output)"}`;
904
1110
  });
905
1111
  return {
906
1112
  content: [
@@ -914,7 +1120,7 @@ export default function subagentExtension(ext, opts) {
914
1120
  }
915
1121
  // ── Single mode ─────────────────────────────────────────────
916
1122
  if (params.agent && params.task) {
917
- const result = await runSingleAgentWithTimeout(ctx.cwd, agents, params.agent, params.task, params.cwd, undefined, signal, onUpdate, makeDetails("single"), _toolCallId, emitSubagentToolProgress, ext, ctx);
1123
+ const result = await runSingleAgentWithTimeout(ctx.cwd, agents, params.agent, params.task, params.cwd, undefined, signal, onUpdate, makeDetails("single"), _toolCallId, emitSubagentToolProgress, ext, ctx, params.maxRetries);
918
1124
  const isError = result.exitCode !== 0 ||
919
1125
  result.stopReason === "error" ||
920
1126
  result.stopReason === "aborted";