@gajae-code/coding-agent 0.11.11 → 0.12.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.
Files changed (344) hide show
  1. package/CHANGELOG.md +131 -4
  2. package/dist/types/async/job-manager.d.ts +17 -3
  3. package/dist/types/cli/read-cli.d.ts +1 -0
  4. package/dist/types/commands/deep-interview.d.ts +9 -0
  5. package/dist/types/commands/harness.d.ts +22 -0
  6. package/dist/types/commands/read.d.ts +6 -0
  7. package/dist/types/config/model-registry.d.ts +4 -0
  8. package/dist/types/config/provider-auth-health.d.ts +14 -0
  9. package/dist/types/config/provider-ranking.d.ts +59 -0
  10. package/dist/types/config/settings-schema.d.ts +83 -1
  11. package/dist/types/config/settings.d.ts +2 -0
  12. package/dist/types/exa/mcp-client.d.ts +10 -1
  13. package/dist/types/exec/bash-executor.d.ts +45 -12
  14. package/dist/types/extensibility/extensions/types.d.ts +38 -4
  15. package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
  16. package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
  17. package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
  18. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
  19. package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
  20. package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
  21. package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
  22. package/dist/types/extensibility/shared-events.d.ts +6 -0
  23. package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
  24. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
  25. package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
  26. package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
  27. package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
  28. package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
  29. package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
  30. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +70 -1
  31. package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
  32. package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
  33. package/dist/types/gjc-runtime/team-runtime.d.ts +27 -1
  34. package/dist/types/gjc-runtime/team-store.d.ts +12 -0
  35. package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
  36. package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
  37. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +17 -0
  38. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
  39. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +31 -80
  40. package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
  41. package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
  42. package/dist/types/main.d.ts +1 -1
  43. package/dist/types/memories/index.d.ts +2 -0
  44. package/dist/types/modes/acp/acp-agent.d.ts +10 -19
  45. package/dist/types/modes/components/assistant-message.d.ts +3 -1
  46. package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
  47. package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
  48. package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
  49. package/dist/types/modes/components/read-tool-group.d.ts +4 -4
  50. package/dist/types/modes/components/session-observer-overlay.d.ts +22 -0
  51. package/dist/types/modes/components/settings-selector.d.ts +11 -0
  52. package/dist/types/modes/components/status-line/gh.d.ts +5 -0
  53. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  54. package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
  55. package/dist/types/modes/controllers/event-controller.d.ts +3 -0
  56. package/dist/types/modes/interactive-mode.d.ts +2 -0
  57. package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
  58. package/dist/types/modes/types.d.ts +2 -0
  59. package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
  60. package/dist/types/reminders/star-reminder.d.ts +3 -13
  61. package/dist/types/runtime-mcp/manager.d.ts +1 -0
  62. package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
  63. package/dist/types/sdk/acp/adapter.d.ts +3 -1
  64. package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
  65. package/dist/types/sdk/broker/transport.d.ts +2 -0
  66. package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
  67. package/dist/types/sdk/bus/chat-daemon-control.d.ts +4 -1
  68. package/dist/types/sdk/bus/config.d.ts +6 -2
  69. package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
  70. package/dist/types/sdk/bus/index.d.ts +44 -1
  71. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +44 -0
  72. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
  73. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
  74. package/dist/types/sdk/bus/reconciliation-store.d.ts +69 -0
  75. package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
  76. package/dist/types/sdk/bus/rich-render.d.ts +2 -0
  77. package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
  78. package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
  79. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +11 -4
  80. package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
  81. package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
  82. package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
  83. package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
  84. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  85. package/dist/types/sdk/host/host.d.ts +2 -0
  86. package/dist/types/sdk/host/query/handlers.d.ts +5 -0
  87. package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
  88. package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
  89. package/dist/types/sdk/prompt-status.d.ts +23 -3
  90. package/dist/types/sdk/session.d.ts +6 -0
  91. package/dist/types/session/agent-session.d.ts +82 -12
  92. package/dist/types/session/artifacts.d.ts +8 -0
  93. package/dist/types/session/blob-store.d.ts +57 -4
  94. package/dist/types/session/internal/managed-session-storage.d.ts +8 -1
  95. package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
  96. package/dist/types/session/session-manager.d.ts +48 -19
  97. package/dist/types/session/session-storage.d.ts +4 -0
  98. package/dist/types/session/streaming-output.d.ts +96 -12
  99. package/dist/types/setup/credential-import.d.ts +12 -0
  100. package/dist/types/skill-state/active-state.d.ts +12 -4
  101. package/dist/types/skill-state/workflow-hud.d.ts +9 -0
  102. package/dist/types/task/executor.d.ts +3 -2
  103. package/dist/types/task/index.d.ts +3 -1
  104. package/dist/types/task/provider-retry-status.d.ts +8 -0
  105. package/dist/types/task/receipt.d.ts +7 -1
  106. package/dist/types/task/types.d.ts +23 -0
  107. package/dist/types/tools/ask-answer-registry.d.ts +2 -2
  108. package/dist/types/tools/bash-interactive.d.ts +4 -1
  109. package/dist/types/tools/bash.d.ts +3 -1
  110. package/dist/types/tools/browser/launch.d.ts +7 -0
  111. package/dist/types/tools/fetch.d.ts +17 -1
  112. package/dist/types/tools/image-gen.d.ts +4 -0
  113. package/dist/types/tools/index.d.ts +4 -0
  114. package/dist/types/tools/output-meta.d.ts +44 -3
  115. package/dist/types/tools/path-utils.d.ts +1 -0
  116. package/dist/types/tools/read-internals.d.ts +12 -0
  117. package/dist/types/tools/read.d.ts +45 -7
  118. package/dist/types/tools/resource-gc.d.ts +4 -0
  119. package/dist/types/tools/review.d.ts +5 -7
  120. package/dist/types/tools/subagent.d.ts +2 -0
  121. package/dist/types/tools/tool-result.d.ts +7 -1
  122. package/dist/types/utils/gh.d.ts +13 -0
  123. package/dist/types/utils/image-resize.d.ts +1 -0
  124. package/dist/types/web/search/providers/kimi.d.ts +2 -0
  125. package/dist/types/web/search/providers/searxng.d.ts +7 -0
  126. package/dist/types/web/search/providers/xai.d.ts +2 -0
  127. package/package.json +11 -13
  128. package/scripts/acp-conformance-agent.ts +218 -0
  129. package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
  130. package/scripts/capture-gjc-bundle-settings.ts +306 -0
  131. package/scripts/capture-sticky-viewport-showcase.ts +292 -0
  132. package/scripts/generate-sdk-operation-inventory.ts +5 -0
  133. package/scripts/resident-memory-bench.ts +1341 -0
  134. package/scripts/run-acp-conformance.ts +285 -0
  135. package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
  136. package/scripts/verify-sticky-viewport-showcase.ts +611 -0
  137. package/src/async/job-manager.ts +78 -20
  138. package/src/capability/index.ts +8 -0
  139. package/src/cli/fast-help.ts +1 -1
  140. package/src/cli/plugin-cli.ts +176 -18
  141. package/src/cli/read-cli.ts +2 -1
  142. package/src/cli.ts +1 -0
  143. package/src/commands/deep-interview.ts +29 -9
  144. package/src/commands/harness.ts +35 -12
  145. package/src/commands/read.ts +11 -2
  146. package/src/commands/team.ts +20 -2
  147. package/src/config/file-lock.ts +11 -2
  148. package/src/config/model-registry.ts +21 -2
  149. package/src/config/provider-auth-health.ts +42 -0
  150. package/src/config/provider-ranking.ts +119 -0
  151. package/src/config/settings-schema.ts +74 -1
  152. package/src/config/settings.ts +246 -108
  153. package/src/coordinator-mcp/question-gate-codec.ts +1 -1
  154. package/src/coordinator-mcp/server.ts +5 -12
  155. package/src/defaults/gjc/skills/deep-interview/SKILL.md +230 -82
  156. package/src/defaults/gjc/skills/ralplan/SKILL.md +77 -41
  157. package/src/defaults/gjc/skills/team/SKILL.md +3 -1
  158. package/src/defaults/gjc/skills/ultragoal/SKILL.md +62 -39
  159. package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
  160. package/src/defaults/gjc-defaults.ts +4 -4
  161. package/src/eval/py/executor.ts +7 -2
  162. package/src/exa/mcp-client.ts +12 -3
  163. package/src/exec/bash-executor.ts +144 -27
  164. package/src/extensibility/extensions/runner.ts +15 -0
  165. package/src/extensibility/extensions/types.ts +46 -5
  166. package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
  167. package/src/extensibility/gjc-plugins/index.ts +19 -2
  168. package/src/extensibility/gjc-plugins/installer.ts +189 -50
  169. package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
  170. package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
  171. package/src/extensibility/gjc-plugins/observability.ts +3 -3
  172. package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
  173. package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
  174. package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
  175. package/src/extensibility/gjc-plugins/schema.ts +84 -12
  176. package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
  177. package/src/extensibility/gjc-plugins/types.ts +141 -0
  178. package/src/extensibility/gjc-plugins/validation.ts +9 -0
  179. package/src/extensibility/shared-events.ts +5 -0
  180. package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -82
  181. package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
  182. package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
  183. package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
  184. package/src/gjc-runtime/deep-interview-state.ts +12 -943
  185. package/src/gjc-runtime/gc-render.ts +1 -0
  186. package/src/gjc-runtime/gc-runtime.ts +11 -1
  187. package/src/gjc-runtime/launch-tmux.ts +25 -6
  188. package/src/gjc-runtime/managed-owner-admission.ts +1 -1
  189. package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
  190. package/src/gjc-runtime/ralplan-runtime.ts +1149 -98
  191. package/src/gjc-runtime/state-runtime.ts +2 -1
  192. package/src/gjc-runtime/state-writer.ts +70 -222
  193. package/src/gjc-runtime/team-launch.ts +42 -5
  194. package/src/gjc-runtime/team-runtime.ts +1085 -40
  195. package/src/gjc-runtime/team-store.ts +32 -0
  196. package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
  197. package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
  198. package/src/gjc-runtime/team-workers.ts +1 -0
  199. package/src/gjc-runtime/tmux-owner-isolation.ts +28 -0
  200. package/src/gjc-runtime/tmux-sessions.ts +58 -13
  201. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
  202. package/src/gjc-runtime/ultragoal-runtime.ts +414 -618
  203. package/src/gjc-runtime/workflow-manifest.generated.json +105 -449
  204. package/src/gjc-runtime/workflow-manifest.ts +38 -247
  205. package/src/hooks/native-skill-hook.ts +17 -4
  206. package/src/hooks/skill-state.ts +1 -23
  207. package/src/internal-urls/docs-index.generated.ts +21 -22
  208. package/src/internal-urls/local-root-gc.ts +127 -0
  209. package/src/main.ts +9 -5
  210. package/src/memories/index.ts +10 -0
  211. package/src/modes/DESIGN.md +98 -0
  212. package/src/modes/acp/acp-agent.ts +339 -191
  213. package/src/modes/acp/acp-event-mapper.ts +14 -7
  214. package/src/modes/acp/acp-mode.ts +39 -3
  215. package/src/modes/components/assistant-message.ts +123 -22
  216. package/src/modes/components/gjc-bundle-settings.ts +508 -0
  217. package/src/modes/components/irc-sidebar.ts +176 -62
  218. package/src/modes/components/model-selector.ts +61 -4
  219. package/src/modes/components/notifications-settings-editor.ts +12 -1
  220. package/src/modes/components/oauth-selector.ts +96 -28
  221. package/src/modes/components/read-tool-group.ts +82 -14
  222. package/src/modes/components/session-observer-overlay.ts +457 -83
  223. package/src/modes/components/settings-selector.ts +116 -23
  224. package/src/modes/components/status-line/gh.ts +16 -0
  225. package/src/modes/components/tool-execution.ts +138 -27
  226. package/src/modes/components/tool-status-header.ts +3 -14
  227. package/src/modes/components/transcript-viewer-overlay.ts +99 -24
  228. package/src/modes/controllers/command-controller.ts +4 -0
  229. package/src/modes/controllers/event-controller.ts +109 -27
  230. package/src/modes/controllers/extension-ui-controller.ts +26 -2
  231. package/src/modes/controllers/input-controller.ts +18 -3
  232. package/src/modes/controllers/selector-controller.ts +127 -36
  233. package/src/modes/interactive-mode.ts +62 -3
  234. package/src/modes/irc-observation-ledger.ts +71 -15
  235. package/src/modes/runtime-init.ts +22 -2
  236. package/src/modes/types.ts +2 -0
  237. package/src/modes/utils/ui-helpers.ts +94 -1
  238. package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
  239. package/src/prompts/agents/architect.md +9 -1
  240. package/src/prompts/agents/critic.md +9 -0
  241. package/src/prompts/system/eager-todo.md +8 -4
  242. package/src/prompts/system/system-prompt.md +11 -5
  243. package/src/prompts/tools/bash.md +5 -5
  244. package/src/prompts/tools/read.md +4 -2
  245. package/src/prompts/tools/search-tool-bm25.md +5 -0
  246. package/src/prompts/tools/task.md +1 -1
  247. package/src/reminders/star-reminder.ts +4 -42
  248. package/src/runtime-mcp/manager.ts +19 -4
  249. package/src/runtime-mcp/smithery-auth.ts +17 -2
  250. package/src/runtime-mcp/smithery-connect.ts +11 -1
  251. package/src/sdk/acp/adapter.ts +22 -6
  252. package/src/sdk/broker/lifecycle.ts +25 -6
  253. package/src/sdk/broker/transport.ts +35 -3
  254. package/src/sdk/bus/attachment-registry.ts +5 -1
  255. package/src/sdk/bus/chat-daemon-cli.ts +4 -39
  256. package/src/sdk/bus/chat-daemon-control.ts +6 -3
  257. package/src/sdk/bus/config.ts +18 -2
  258. package/src/sdk/bus/control-drain-lease.ts +104 -0
  259. package/src/sdk/bus/index.ts +984 -146
  260. package/src/sdk/bus/kind-aware-reconciliation.ts +317 -0
  261. package/src/sdk/bus/lifecycle-commands.ts +4 -1
  262. package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
  263. package/src/sdk/bus/prompt-reconciliation.ts +2 -1
  264. package/src/sdk/bus/reconciliation-store.ts +303 -0
  265. package/src/sdk/bus/rich-draft.ts +1 -1
  266. package/src/sdk/bus/rich-render.ts +2 -2
  267. package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
  268. package/src/sdk/bus/telegram-cli.ts +33 -8
  269. package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
  270. package/src/sdk/bus/telegram-daemon-contract.ts +11 -4
  271. package/src/sdk/bus/telegram-daemon.ts +916 -23
  272. package/src/sdk/bus/telegram-reference.ts +40 -3
  273. package/src/sdk/bus/threaded-render.ts +48 -3
  274. package/src/sdk/bus/topic-registry.ts +20 -0
  275. package/src/sdk/host/control/dispatch.ts +5 -1
  276. package/src/sdk/host/control/operations.ts +1 -1
  277. package/src/sdk/host/host.ts +23 -1
  278. package/src/sdk/host/query/handlers.ts +55 -0
  279. package/src/sdk/host/query/revision-store.ts +36 -2
  280. package/src/sdk/host/reverse-leases.ts +44 -7
  281. package/src/sdk/mcp/server.ts +46 -18
  282. package/src/sdk/prompt-status.ts +16 -3
  283. package/src/sdk/protocol/operation-inventory.generated.json +51 -0
  284. package/src/sdk/protocol/operation-registry.ts +7 -2
  285. package/src/sdk/session.ts +101 -10
  286. package/src/session/agent-session.ts +1286 -220
  287. package/src/session/artifacts.ts +22 -0
  288. package/src/session/auth-broker-config.ts +10 -3
  289. package/src/session/blob-store.ts +915 -24
  290. package/src/session/internal/managed-session-scope.ts +44 -6
  291. package/src/session/internal/managed-session-storage.ts +48 -6
  292. package/src/session/memory-guard-checkpoint-participant.ts +131 -0
  293. package/src/session/session-manager.ts +2364 -438
  294. package/src/session/session-storage.ts +9 -1
  295. package/src/session/streaming-output.ts +500 -111
  296. package/src/setup/credential-import.ts +75 -13
  297. package/src/setup/provider-onboarding.ts +19 -4
  298. package/src/skill-state/active-state.ts +32 -10
  299. package/src/skill-state/workflow-hud.ts +42 -2
  300. package/src/skill-state/workflow-mutation-guard.ts +560 -8
  301. package/src/task/executor.ts +122 -39
  302. package/src/task/index.ts +23 -14
  303. package/src/task/provider-retry-status.ts +16 -0
  304. package/src/task/receipt.ts +23 -7
  305. package/src/task/render.ts +6 -2
  306. package/src/task/types.ts +108 -0
  307. package/src/tools/ask-answer-registry.ts +12 -6
  308. package/src/tools/ask.ts +169 -118
  309. package/src/tools/ast-edit.ts +1 -0
  310. package/src/tools/ast-grep.ts +1 -0
  311. package/src/tools/bash-interactive.ts +8 -3
  312. package/src/tools/bash.ts +503 -60
  313. package/src/tools/browser/launch.ts +41 -6
  314. package/src/tools/fetch.ts +114 -23
  315. package/src/tools/find.ts +1 -0
  316. package/src/tools/image-gen.ts +29 -5
  317. package/src/tools/index.ts +4 -0
  318. package/src/tools/output-meta.ts +281 -20
  319. package/src/tools/path-utils.ts +8 -3
  320. package/src/tools/read-internals.ts +44 -0
  321. package/src/tools/read.ts +1560 -310
  322. package/src/tools/resource-gc.ts +182 -18
  323. package/src/tools/review.ts +5 -7
  324. package/src/tools/search.ts +1 -0
  325. package/src/tools/subagent-render.ts +6 -2
  326. package/src/tools/subagent.ts +6 -0
  327. package/src/tools/telegram-send.ts +6 -3
  328. package/src/tools/tool-result.ts +14 -1
  329. package/src/utils/gh.ts +39 -0
  330. package/src/utils/image-resize.ts +3 -0
  331. package/src/web/search/providers/anthropic.ts +4 -4
  332. package/src/web/search/providers/codex.ts +1 -1
  333. package/src/web/search/providers/kimi.ts +15 -5
  334. package/src/web/search/providers/searxng.ts +47 -4
  335. package/src/web/search/providers/xai.ts +7 -2
  336. package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
  337. package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
  338. package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
  339. package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
  340. package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
  341. package/src/gjc-runtime/deep-interview-draft.ts +0 -843
  342. package/src/gjc-runtime/deep-interview-payload.ts +0 -262
  343. package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
  344. package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
@@ -44,23 +44,25 @@ import { SessionManager } from "../session/session-manager";
44
44
  import { truncateTail } from "../session/streaming-output";
45
45
  import type { ContextFileEntry } from "../tools";
46
46
  import { jtdToJsonSchema, normalizeSchema } from "../tools/jtd-to-json-schema";
47
- import { type ReportFindingDetails, toReviewFinding } from "../tools/review";
47
+ import type { ReportFindingDetails } from "../tools/review";
48
48
  import { ToolAbortError } from "../tools/tool-errors";
49
49
  import type { EventBus } from "../utils/event-bus";
50
50
  import { buildNamedToolChoiceResult } from "../utils/tool-choice";
51
51
  import type { WorkspaceTree } from "../workspace-tree";
52
52
  import { validateAllocatedTaskId } from "./id";
53
- import { classifyProviderRetry, providerNameFromModel } from "./provider-retry-status";
53
+ import { classifyProviderRetryFromTransport, providerNameFromModel } from "./provider-retry-status";
54
54
  import { subprocessToolRegistry } from "./subprocess-tool-registry";
55
55
  import { persistTaskTokenLog, taskTokenLogFromUsage } from "./token-log";
56
56
  import {
57
57
  type AgentDefinition,
58
58
  type AgentProgress,
59
+ createSetupFailureSummary,
59
60
  hasCompleteUsageCostBreakdown,
60
61
  MAX_OUTPUT_BYTES,
61
62
  MAX_OUTPUT_LINES,
62
63
  type ModelSubstitutionWarning,
63
- type ReviewFinding,
64
+ type ReviewFindingsArtifactRef,
65
+ type SetupFailureSummary,
64
66
  type SingleResult,
65
67
  TASK_SUBAGENT_EVENT_CHANNEL,
66
68
  TASK_SUBAGENT_LIFECYCLE_CHANNEL,
@@ -241,6 +243,8 @@ export interface ExecutorOptions {
241
243
  * subagents, and a main-model fast-mode auto-disable does not clobber it.
242
244
  */
243
245
  inheritedServiceTier?: ServiceTier;
246
+ /** Resolve whether the effective subagent tier grants fast mode for the selected provider. */
247
+ isFastForSubagentProvider?: (provider?: string) => boolean;
244
248
  /** Override local:// protocol options so subagent shares parent's local:// root */
245
249
  localProtocolOptions?: LocalProtocolOptions;
246
250
  /**
@@ -291,11 +295,13 @@ export class ManagedTaskPersistence {
291
295
  }
292
296
 
293
297
  async publishOutput(rawOutput: string, metadata: Uint8Array): Promise<void> {
294
- await this.#artifacts.publishManagedOutputGeneration(
295
- `${this.#taskId}.md.selector.json`,
296
- `${this.#taskId}.md`,
297
- Buffer.from(rawOutput, "utf8"),
298
- metadata,
298
+ await withArtifactManagerFinalizationTurn(this.#artifacts, () =>
299
+ this.#artifacts.publishManagedOutputGeneration(
300
+ `${this.#taskId}.md.selector.json`,
301
+ `${this.#taskId}.md`,
302
+ Buffer.from(rawOutput, "utf8"),
303
+ metadata,
304
+ ),
299
305
  );
300
306
  }
301
307
  }
@@ -304,6 +310,59 @@ export function createManagedTaskPersistence(artifacts: ArtifactManager, taskId:
304
310
  return new ManagedTaskPersistence(artifacts, taskId);
305
311
  }
306
312
 
313
+ const MAX_REVIEW_FINDINGS_ARTIFACT_BYTES = 16 * 1024 * 1024;
314
+ const REVIEW_FINDINGS_ARTIFACT_FAILURE = "Review findings artifact publication failed.";
315
+ const artifactManagerFinalizationTails = new WeakMap<ArtifactManager, Promise<void>>();
316
+
317
+ interface ReviewFindingsArtifactPayload {
318
+ version: 1;
319
+ kind: "review-findings";
320
+ taskId: string;
321
+ findingCount: number;
322
+ findings: ReportFindingDetails[];
323
+ }
324
+
325
+ async function withArtifactManagerFinalizationTurn<T>(
326
+ manager: ArtifactManager,
327
+ operation: () => Promise<T>,
328
+ ): Promise<T> {
329
+ const priorTail = artifactManagerFinalizationTails.get(manager);
330
+ const turn = Promise.withResolvers<void>();
331
+ artifactManagerFinalizationTails.set(manager, turn.promise);
332
+
333
+ try {
334
+ await priorTail?.catch(() => undefined);
335
+ return await operation();
336
+ } finally {
337
+ turn.resolve();
338
+ if (artifactManagerFinalizationTails.get(manager) === turn.promise) {
339
+ artifactManagerFinalizationTails.delete(manager);
340
+ }
341
+ }
342
+ }
343
+
344
+ async function publishReviewFindingsArtifact(
345
+ manager: ArtifactManager,
346
+ taskId: string,
347
+ findings: ReportFindingDetails[],
348
+ ): Promise<ReviewFindingsArtifactRef> {
349
+ const payload: ReviewFindingsArtifactPayload = {
350
+ version: 1,
351
+ kind: "review-findings",
352
+ taskId,
353
+ findingCount: findings.length,
354
+ findings,
355
+ };
356
+ const serialized = JSON.stringify(payload, null, 2);
357
+ const sizeBytes = Buffer.byteLength(serialized, "utf8");
358
+ if (sizeBytes > MAX_REVIEW_FINDINGS_ARTIFACT_BYTES) throw new Error("review findings artifact exceeds limit");
359
+ const sha256 = createHash("sha256").update(serialized).digest("hex");
360
+ const artifactId = await withArtifactManagerFinalizationTurn(manager, () =>
361
+ manager.save(serialized, "review-findings", { maxBytes: sizeBytes }),
362
+ );
363
+ return { uri: `artifact://${artifactId}`, sizeBytes, sha256, findingCount: findings.length };
364
+ }
365
+
307
366
  export function renderSubagentUserPrompt(assignment: string, independentMode: boolean): string {
308
367
  return prompt.render(subagentUserPromptTemplate, { assignment: assignment.trim(), independentMode });
309
368
  }
@@ -439,21 +498,8 @@ function extractCompletionData(parsed: unknown): unknown {
439
498
  return parsed;
440
499
  }
441
500
 
442
- function normalizeCompleteData(data: unknown, reportFindings?: ReviewFinding[]): unknown {
443
- let normalized = parseStringifiedJson(data ?? null);
444
- if (
445
- Array.isArray(reportFindings) &&
446
- reportFindings.length > 0 &&
447
- normalized &&
448
- typeof normalized === "object" &&
449
- !Array.isArray(normalized)
450
- ) {
451
- const record = normalized as Record<string, unknown>;
452
- if (!("findings" in record)) {
453
- normalized = { ...record, findings: reportFindings };
454
- }
455
- }
456
- return normalized;
501
+ function normalizeCompleteData(data: unknown): unknown {
502
+ return parseStringifiedJson(data ?? null);
457
503
  }
458
504
 
459
505
  function resolveFallbackCompletion(rawOutput: string, outputSchema: unknown): { data: unknown } | null {
@@ -480,7 +526,6 @@ interface FinalizeSubprocessOutputArgs {
480
526
  doneAborted: boolean;
481
527
  signalAborted: boolean;
482
528
  yieldItems?: YieldItem[];
483
- reportFindings?: ReviewFinding[];
484
529
  outputSchema: unknown;
485
530
  }
486
531
 
@@ -541,7 +586,7 @@ function buildPlaceholderYieldOutcome(
541
586
 
542
587
  export function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): FinalizeSubprocessOutputResult {
543
588
  let { rawOutput, exitCode, stderr } = args;
544
- const { yieldItems, reportFindings, doneAborted, signalAborted, outputSchema } = args;
589
+ const { yieldItems, doneAborted, signalAborted, outputSchema } = args;
545
590
  let abortedViaYield = false;
546
591
  const hasYield = Array.isArray(yieldItems) && yieldItems.length > 0;
547
592
 
@@ -561,7 +606,7 @@ export function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): Fi
561
606
  if (submitData === null || submitData === undefined) {
562
607
  rawOutput = rawOutput ? `${SUBAGENT_WARNING_NULL_YIELD}\n\n${rawOutput}` : SUBAGENT_WARNING_NULL_YIELD;
563
608
  } else {
564
- const completeData = normalizeCompleteData(submitData, reportFindings);
609
+ const completeData = normalizeCompleteData(submitData);
565
610
  const { validator, error: schemaError } = buildOutputValidator(outputSchema);
566
611
  if (schemaError) {
567
612
  const outcome = buildSchemaViolationOutcome(
@@ -608,7 +653,7 @@ export function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): Fi
608
653
  const hasOutputSchema = normalizedSchema !== undefined && !schemaError;
609
654
  const fallback = allowFallback ? resolveFallbackCompletion(rawOutput, outputSchema) : null;
610
655
  if (fallback) {
611
- const completeData = normalizeCompleteData(fallback.data, reportFindings);
656
+ const completeData = normalizeCompleteData(fallback.data);
612
657
  const { validator } = buildOutputValidator(outputSchema);
613
658
  const placeholderPath = findPlaceholderYieldPath(completeData);
614
659
  if (placeholderPath) {
@@ -873,6 +918,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
873
918
  let sessionEventOrdinal = 0;
874
919
  let retryStartOrdinal = 0;
875
920
  const seenAssistantMessages = new WeakSet<AgentMessage>();
921
+ let llmRequestStarted = false;
876
922
  const seenAssistantMessageIdentities = new Set<string>();
877
923
 
878
924
  // Accumulate usage incrementally from message_end events (no memory for streaming events)
@@ -965,7 +1011,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
965
1011
  task,
966
1012
  assignment,
967
1013
  progress: progressSnapshot,
968
- sessionFile: null,
1014
+ sessionFile: sessionFile ?? undefined,
969
1015
  });
970
1016
  }
971
1017
  lastProgressEmitMs = Date.now();
@@ -1380,6 +1426,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
1380
1426
  error?: string;
1381
1427
  aborted?: boolean;
1382
1428
  abortReason?: string;
1429
+ setupFailure?: SetupFailureSummary;
1383
1430
  durationMs: number;
1384
1431
  }> => {
1385
1432
  const sessionAbortController = new AbortController();
@@ -1387,6 +1434,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
1387
1434
  let error: string | undefined;
1388
1435
  let aborted = false;
1389
1436
  let abortReasonText: string | undefined;
1437
+ let setupFailure: SetupFailureSummary | undefined;
1390
1438
  const checkAbort = () => {
1391
1439
  if (abortSignal.aborted) {
1392
1440
  aborted = abortReason === "signal" || runtimeLimitExceeded || abortReason === undefined;
@@ -1463,6 +1511,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
1463
1511
  resolvedModelString = formatModelString(model);
1464
1512
  activeProviderModelString = resolvedModelString;
1465
1513
  }
1514
+ progress.fastMode = model ? (options.isFastForSubagentProvider?.(model.provider) ?? false) : false;
1466
1515
  if (authFallbackUsed && model && requestedModel) {
1467
1516
  modelSubstitutionWarning = {
1468
1517
  requested: formatModelString(requestedModel),
@@ -1706,7 +1755,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
1706
1755
  agentSource: agent.source,
1707
1756
  description: options.description,
1708
1757
  status: "started",
1709
- sessionFile: null,
1758
+ sessionFile: sessionFile ?? undefined,
1710
1759
  index,
1711
1760
  });
1712
1761
  }
@@ -1801,7 +1850,9 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
1801
1850
  {
1802
1851
  getModel: () => session.model,
1803
1852
  isIdle: () => !session.isStreaming,
1853
+ getActivePromptHandle: () => session.activePromptHandle,
1804
1854
  abort: () => session.abort(),
1855
+ abortPromptAndWait: (handle, options) => session.abortPromptAndWait(handle, options),
1805
1856
  hasPendingMessages: () => session.queuedMessageCount > 0,
1806
1857
  getPendingMessageCounts: () => session.pendingMessageCounts,
1807
1858
  getTranscript: () => session.getTranscript(),
@@ -1842,11 +1893,15 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
1842
1893
  for (const message of session.messages) {
1843
1894
  if (message.role === "assistant") rememberAssistantMessage(message);
1844
1895
  }
1896
+ const failedAssistant = session.getLastAssistantMessage();
1845
1897
  progress.retryState = {
1846
1898
  attempt: event.attempt,
1847
1899
  maxAttempts: event.maxAttempts,
1848
1900
  unbounded: event.unbounded,
1849
- kind: classifyProviderRetry(event.errorMessage),
1901
+ kind: classifyProviderRetryFromTransport({
1902
+ providerCode: failedAssistant?.transportFailure?.providerCode,
1903
+ errorMessage: event.errorMessage,
1904
+ }),
1850
1905
  provider: providerNameFromModel(
1851
1906
  activeProviderModelString ?? lastAssistantModelString ?? resolvedModelString,
1852
1907
  ),
@@ -1905,16 +1960,24 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
1905
1960
  }
1906
1961
  }
1907
1962
  const runMode = options.runMode ?? "initial";
1963
+ const markLlmRequestStarted = () => {
1964
+ llmRequestStarted = true;
1965
+ };
1966
+ const promptOptions = {
1967
+ attribution: "agent" as const,
1968
+ // A prompt is an LLM request only after AgentSession accepts its
1969
+ // preflight fence. Rejections remain setup failures.
1970
+ onPreflightAccepted: markLlmRequestStarted,
1971
+ onPreflightAcceptCommit: markLlmRequestStarted,
1972
+ };
1908
1973
  if (runMode === "message") {
1909
- await awaitAbortable(session.prompt(options.resumeMessage ?? "", { attribution: "agent" }));
1974
+ await awaitAbortable(session.prompt(options.resumeMessage ?? "", promptOptions));
1910
1975
  await awaitAbortable(session.waitForIdle());
1911
1976
  } else if (runMode === "resume") {
1912
- await awaitAbortable(
1913
- session.prompt("Continue from the paused subagent session state.", { attribution: "agent" }),
1914
- );
1977
+ await awaitAbortable(session.prompt("Continue from the paused subagent session state.", promptOptions));
1915
1978
  await awaitAbortable(session.waitForIdle());
1916
1979
  } else {
1917
- await awaitAbortable(session.prompt(task, { attribution: "agent" }));
1980
+ await awaitAbortable(session.prompt(task, promptOptions));
1918
1981
  await awaitAbortable(session.waitForIdle());
1919
1982
  }
1920
1983
 
@@ -1991,6 +2054,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
1991
2054
  exitCode = 1;
1992
2055
  if (!abortSignal.aborted) {
1993
2056
  error = err instanceof Error ? err.stack || err.message : String(err);
2057
+ if (!llmRequestStarted) setupFailure = createSetupFailureSummary(err);
1994
2058
  }
1995
2059
  } finally {
1996
2060
  if (abortSignal.aborted) {
@@ -2026,6 +2090,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
2026
2090
  error,
2027
2091
  aborted,
2028
2092
  abortReason: aborted ? abortReasonText : undefined,
2093
+ setupFailure,
2029
2094
  durationMs: Date.now() - startTime,
2030
2095
  };
2031
2096
  };
@@ -2052,7 +2117,6 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
2052
2117
  let rawOutput = finalOutputChunks.length > 0 ? finalOutputChunks.join("") : outputChunks.join("");
2053
2118
  const yieldItems = progress.extractedToolData?.yield as YieldItem[] | undefined;
2054
2119
  const reportFindingDetails = progress.extractedToolData?.report_finding as ReportFindingDetails[] | undefined;
2055
- const reportFindings: ReviewFinding[] | undefined = reportFindingDetails?.map(toReviewFinding);
2056
2120
  const finalized = finalizeSubprocessOutput({
2057
2121
  rawOutput,
2058
2122
  exitCode,
@@ -2060,12 +2124,25 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
2060
2124
  doneAborted: Boolean(done.aborted),
2061
2125
  signalAborted: Boolean(signal?.aborted),
2062
2126
  yieldItems,
2063
- reportFindings,
2064
2127
  outputSchema,
2065
2128
  });
2066
2129
  rawOutput = finalized.rawOutput;
2067
2130
  exitCode = finalized.exitCode;
2068
2131
  stderr = finalized.stderr;
2132
+ let reviewFindingsRef: ReviewFindingsArtifactRef | undefined;
2133
+ let reviewFindingsPublicationFailed = false;
2134
+ if (reportFindingDetails && reportFindingDetails.length > 0) {
2135
+ try {
2136
+ const manager = options.parentArtifactManager;
2137
+ if (!manager) throw new Error("review findings artifact authority unavailable");
2138
+ reviewFindingsRef = await publishReviewFindingsArtifact(manager, id, reportFindingDetails);
2139
+ } catch {
2140
+ reviewFindingsPublicationFailed = true;
2141
+ exitCode = 1;
2142
+ stderr = REVIEW_FINDINGS_ARTIFACT_FAILURE;
2143
+ paused = false;
2144
+ }
2145
+ }
2069
2146
  const lastYield = yieldItems?.[yieldItems.length - 1];
2070
2147
  const yieldAbortReason = lastYield?.status === "aborted" ? lastYield.error || "Subagent aborted task" : undefined;
2071
2148
  const { abortedViaYield, hasYield } = finalized;
@@ -2122,7 +2199,9 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
2122
2199
  exitCode = 1;
2123
2200
  }
2124
2201
  const wasAborted =
2125
- runtimeLimitExceeded || abortedViaYield || (!hasYield && (done.aborted || signal?.aborted || false));
2202
+ runtimeLimitExceeded ||
2203
+ (!reviewFindingsPublicationFailed &&
2204
+ (abortedViaYield || (!hasYield && (done.aborted || signal?.aborted || false))));
2126
2205
  const finalAbortReason = wasAborted
2127
2206
  ? runtimeLimitExceeded
2128
2207
  ? resolveAbortReasonText()
@@ -2130,6 +2209,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
2130
2209
  ? yieldAbortReason
2131
2210
  : (done.abortReason ?? (signal?.aborted ? resolveSignalAbortReason() : resolveAbortReasonText()))
2132
2211
  : undefined;
2212
+ progress.setupFailure = done.setupFailure;
2133
2213
  progress.status = paused ? "paused" : wasAborted ? "aborted" : exitCode === 0 ? "completed" : "failed";
2134
2214
  scheduleProgress(true);
2135
2215
 
@@ -2141,7 +2221,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
2141
2221
  agentSource: agent.source,
2142
2222
  description: options.description,
2143
2223
  status: progress.status as "completed" | "failed" | "aborted" | "paused",
2144
- sessionFile: null,
2224
+ sessionFile: sessionFile ?? undefined,
2145
2225
  index,
2146
2226
  });
2147
2227
  }
@@ -2165,7 +2245,9 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
2165
2245
  contextWindow: progress.contextWindow,
2166
2246
  modelOverride,
2167
2247
  modelSubstitutionWarning,
2248
+ fastMode: progress.fastMode,
2168
2249
  error: exitCode !== 0 && stderr ? stderr : undefined,
2250
+ setupFailure: done.setupFailure,
2169
2251
  aborted: wasAborted,
2170
2252
  abortReason: finalAbortReason,
2171
2253
  paused,
@@ -2175,5 +2257,6 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
2175
2257
  extractedToolData: progress.extractedToolData,
2176
2258
  retryFailure: progress.retryFailure,
2177
2259
  outputMeta,
2260
+ reviewFindingsRef,
2178
2261
  };
2179
2262
  }
package/src/task/index.ts CHANGED
@@ -19,7 +19,7 @@ import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "@gajae
19
19
  import type { Model, Usage } from "@gajae-code/ai";
20
20
  import { $pickenv, prompt, Snowflake } from "@gajae-code/utils";
21
21
  import type { ToolSession } from "..";
22
- import { AsyncJobManager, OwnerSubagentShutdownError, type ResumeRunner } from "../async";
22
+ import { AsyncJobManager, OwnerSubagentShutdownError, type ResumeRunner, type SubagentRunOutcome } from "../async";
23
23
  import { resolveAgentModelPatterns } from "../config/model-resolver";
24
24
  import type { Theme } from "../modes/theme/theme";
25
25
  import planModeSubagentPrompt from "../prompts/system/plan-mode-subagent.md" with { type: "text" };
@@ -98,6 +98,23 @@ function isTaskResumeDescriptor(value: unknown): value is TaskResumeDescriptor {
98
98
  function renderTaskAssignment(assignment: string, simpleMode: TaskSimpleMode): string {
99
99
  return renderSubagentUserPrompt(assignment, simpleMode === "independent");
100
100
  }
101
+
102
+ export function subagentRunOutcomeFromSingleResult(
103
+ finalText: string,
104
+ singleResult: Pick<SingleResult, "aborted" | "exitCode" | "paused" | "setupFailure"> | undefined,
105
+ ): string | SubagentRunOutcome {
106
+ if (singleResult?.paused) return { kind: "paused" };
107
+ if (singleResult && ((singleResult.aborted ?? false) || singleResult.exitCode !== 0)) {
108
+ return {
109
+ kind: "failed",
110
+ text: finalText,
111
+ ...(singleResult.setupFailure && !singleResult.aborted
112
+ ? { setupFailureSummary: singleResult.setupFailure.summary }
113
+ : {}),
114
+ };
115
+ }
116
+ return finalText;
117
+ }
101
118
  function createUsageTotals(): Usage {
102
119
  return {
103
120
  input: 0,
@@ -655,15 +672,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
655
672
  );
656
673
  const finalText = result.content.find(part => part.type === "text")?.text ?? "(no output)";
657
674
  const singleResult = result.details?.results[0];
658
- if (singleResult?.paused) return { kind: "paused" };
659
- // A resumed subprocess that aborted or exited non-zero is a failed
660
- // resume, not a completed one. Throw the rendered failure summary
661
- // (finalText) so the leg is reported failed instead of being
662
- // returned as successful continuation.
663
- if (singleResult && ((singleResult.aborted ?? false) || singleResult.exitCode !== 0)) {
664
- throw new Error(finalText);
665
- }
666
- return finalText;
675
+ return subagentRunOutcomeFromSingleResult(finalText, singleResult);
667
676
  },
668
677
  {
669
678
  id: `${descriptor.task.id}-resume-${Snowflake.next()}`,
@@ -809,6 +818,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
809
818
  }
810
819
  : undefined;
811
820
  progress.retryState = undefined;
821
+ progress.setupFailure = singleResult?.setupFailure;
812
822
  }
813
823
  completedJobs += 1;
814
824
  if (singleResult && ((singleResult.aborted ?? false) || singleResult.exitCode !== 0)) {
@@ -831,10 +841,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
831
841
  `Background task batch complete: ${completedJobs}/${taskItems.length} finished.`,
832
842
  );
833
843
  }
834
- if (singleResult?.paused) {
835
- return { kind: "paused" };
836
- }
837
- return finalText;
844
+ return subagentRunOutcomeFromSingleResult(finalText, singleResult);
838
845
  } catch (error) {
839
846
  if (progress) {
840
847
  progress.status = "failed";
@@ -1481,6 +1488,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1481
1488
  agentRegistry: this.session.agentRegistry,
1482
1489
  settings: this.session.settings,
1483
1490
  inheritedServiceTier: this.session.serviceTier,
1491
+ isFastForSubagentProvider: provider => this.session.isFastForSubagentProvider?.(provider) ?? false,
1484
1492
  contextFiles,
1485
1493
  skills: availableSkills,
1486
1494
  autoloadSkills: resolvedAutoloadSkills,
@@ -1554,6 +1562,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1554
1562
  agentRegistry: this.session.agentRegistry,
1555
1563
  settings: this.session.settings,
1556
1564
  inheritedServiceTier: this.session.serviceTier,
1565
+ isFastForSubagentProvider: provider => this.session.isFastForSubagentProvider?.(provider) ?? false,
1557
1566
  contextFiles,
1558
1567
  skills: availableSkills,
1559
1568
  autoloadSkills: resolvedAutoloadSkills,
@@ -4,8 +4,24 @@ export type ProviderRetryKind = NonNullable<AgentProgress["retryState"]>["kind"]
4
4
 
5
5
  const FIRST_EVENT_TIMEOUT_PATTERN = /stream timed out while waiting for the first event/i;
6
6
  const IDLE_STREAM_STALL_PATTERN = /stream stalled while waiting for the next event/i;
7
+ const STREAM_FIRST_EVENT_TIMEOUT_PROVIDER_CODE = "stream_first_event_timeout";
7
8
 
8
9
  export function classifyProviderRetry(errorMessage: string): ProviderRetryKind {
10
+ return classifyProviderRetryFromTransport({ errorMessage });
11
+ }
12
+
13
+ /**
14
+ * Prefer typed transport facts when present; fall back to message regex for
15
+ * message-only callers that never received `transportFailure.providerCode`.
16
+ */
17
+ export function classifyProviderRetryFromTransport(facts: {
18
+ providerCode?: string;
19
+ errorMessage?: string;
20
+ }): ProviderRetryKind {
21
+ if (facts.providerCode?.toLowerCase() === STREAM_FIRST_EVENT_TIMEOUT_PROVIDER_CODE) {
22
+ return "first_event_timeout";
23
+ }
24
+ const errorMessage = facts.errorMessage ?? "";
9
25
  if (FIRST_EVENT_TIMEOUT_PATTERN.test(errorMessage)) return "first_event_timeout";
10
26
  if (IDLE_STREAM_STALL_PATTERN.test(errorMessage)) return "idle_stream_stall";
11
27
  return "provider_error";
@@ -1,4 +1,9 @@
1
- import { hasCompleteUsageCostBreakdown, type SingleResult, type TaskToolDetails } from "./types";
1
+ import {
2
+ hasCompleteUsageCostBreakdown,
3
+ type ReviewFindingsArtifactRef,
4
+ type SingleResult,
5
+ type TaskToolDetails,
6
+ } from "./types";
2
7
  export interface TaskRoi {
3
8
  tokens: number;
4
9
  contextTokens?: number;
@@ -29,11 +34,13 @@ export interface TaskResultReceipt {
29
34
  contextWindow?: number;
30
35
  modelOverride?: string | string[];
31
36
  modelSubstitutionWarning?: SingleResult["modelSubstitutionWarning"];
37
+ fastMode?: boolean;
32
38
  usage?: SingleResult["usage"];
33
39
  cost?: number;
34
40
  usageCostBreakdownComplete?: true;
35
41
  branchName?: string;
36
42
  retryFailure?: { attempt: number; errorSummary: string };
43
+ setupFailure?: { summary: string };
37
44
  errorSummary?: string;
38
45
  abortSummary?: string;
39
46
  preview: string;
@@ -44,6 +51,8 @@ export interface TaskResultReceipt {
44
51
  overallCorrectness?: string;
45
52
  findingCount: number;
46
53
  findings?: Array<{ severity?: string; summary: string }>;
54
+ /** Canonical full-fidelity findings; inline summaries are display-only. */
55
+ findingsRef?: ReviewFindingsArtifactRef;
47
56
  };
48
57
  extractedToolCounts?: Record<string, number>;
49
58
  forkContext?: SingleResult["forkContext"];
@@ -103,6 +112,9 @@ function normalizeReviewFindingSeverity(severity: unknown, priority: unknown): s
103
112
 
104
113
  function buildSafeSynopsis(raw: SingleResult, outputRef: TaskResultReceipt["outputRef"]): string {
105
114
  const status = getStatus(raw);
115
+ if (raw.setupFailure) {
116
+ return `Task ${status} during setup: ${raw.setupFailure.summary}`;
117
+ }
106
118
  if (raw.modelSubstitutionWarning) {
107
119
  return `Task ${status}; requested model substituted from ${raw.modelSubstitutionWarning.requested} to ${raw.modelSubstitutionWarning.effective}.`;
108
120
  }
@@ -131,32 +143,34 @@ function getStatus(raw: SingleResult): TaskResultReceipt["status"] {
131
143
 
132
144
  function buildReview(raw: SingleResult): TaskResultReceipt["review"] | undefined {
133
145
  const data = raw.extractedToolData;
134
- if (!data) return undefined;
135
- const yields = Array.isArray(data.yield) ? data.yield : [];
146
+ const findingsRef = raw.reviewFindingsRef;
147
+ const yields = Array.isArray(data?.yield) ? data.yield : [];
136
148
  const reviewYield = yields
137
149
  .map(item => (item && typeof item === "object" ? (item as { data?: unknown }).data : undefined))
138
150
  .findLast(item => item && typeof item === "object" && "overall_correctness" in item) as
139
151
  | { overall_correctness?: unknown }
140
152
  | undefined;
141
- const rawFindings = Array.isArray(data.report_finding) ? data.report_finding : [];
153
+ const rawFindings = Array.isArray(data?.report_finding) ? data.report_finding : [];
142
154
  const findings = rawFindings.slice(0, 20).map(item => {
143
155
  const value = item && typeof item === "object" ? (item as Record<string, unknown>) : {};
144
156
  const severity = normalizeReviewFindingSeverity(value.severity, value.priority);
145
157
  const summaryValue = value.summary ?? value.title ?? value.message ?? value.body ?? "finding";
146
158
  return { severity, summary: truncateText(String(summaryValue), 200) ?? "finding" };
147
159
  });
148
- if (!reviewYield && findings.length === 0) return undefined;
160
+ if (!reviewYield && findings.length === 0 && !findingsRef) return undefined;
149
161
  return {
150
162
  overallCorrectness: truncateText(
151
163
  typeof reviewYield?.overall_correctness === "string" ? reviewYield.overall_correctness : undefined,
152
164
  200,
153
165
  ),
154
- findingCount: rawFindings.length,
166
+ findingCount: findingsRef?.findingCount ?? rawFindings.length,
155
167
  findings: findings.length > 0 ? findings : undefined,
168
+ findingsRef,
156
169
  };
157
170
  }
158
171
 
159
172
  function hasReviewFindings(raw: SingleResult): boolean {
173
+ if (raw.reviewFindingsRef) return true;
160
174
  const findings = raw.extractedToolData?.report_finding;
161
175
  return Array.isArray(findings) && findings.length > 0;
162
176
  }
@@ -251,10 +265,12 @@ export function buildTaskReceipt(raw: SingleResult): TaskResultReceipt {
251
265
  usageCostBreakdownComplete:
252
266
  raw.usageCostBreakdownComplete === true && hasCompleteUsageCostBreakdown(raw.usage) ? true : undefined,
253
267
  branchName: raw.branchName,
268
+ fastMode: raw.fastMode,
254
269
  retryFailure: raw.retryFailure
255
270
  ? { attempt: raw.retryFailure.attempt, errorSummary: "Retry failure recorded." }
256
271
  : undefined,
257
- errorSummary: raw.error ? "Error recorded." : undefined,
272
+ errorSummary: raw.setupFailure?.summary ?? (raw.error ? "Error recorded." : undefined),
273
+ setupFailure: raw.setupFailure ? { summary: raw.setupFailure.summary } : undefined,
258
274
  abortSummary: raw.abortReason ? "Abort reason recorded." : undefined,
259
275
  preview,
260
276
  previewTruncated: false,
@@ -561,7 +561,7 @@ function renderAgentProgress(
561
561
  const description = progress.description?.trim();
562
562
  const displayId = formatTaskId(progress.id);
563
563
  const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
564
- let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}`;
564
+ let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}${progress.fastMode && theme.icon.fast ? ` ${theme.icon.fast}` : ""}`;
565
565
 
566
566
  // A provider recovery loop is operationally distinct from normal agent work.
567
567
  if (progress.retryState && progress.status === "running") {
@@ -594,6 +594,10 @@ function renderAgentProgress(
594
594
  )}`,
595
595
  );
596
596
  }
597
+ if (progress.setupFailure && progress.status !== "running") {
598
+ const summary = `Setup failure: ${truncateToWidth(replaceTabs(progress.setupFailure.summary), 80)}`;
599
+ lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("error", summary)}`);
600
+ }
597
601
 
598
602
  // Current tool (if running) or most recent completed tool
599
603
  if (progress.status === "running") {
@@ -862,7 +866,7 @@ function renderAgentResult(result: TaskResultReceipt, isLast: boolean, expanded:
862
866
  const description = result.description?.trim();
863
867
  const displayId = formatTaskId(result.id);
864
868
  const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
865
- let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)} ${formatBadge(
869
+ let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}${result.fastMode && theme.icon.fast ? ` ${theme.icon.fast}` : ""} ${formatBadge(
866
870
  statusText,
867
871
  iconColor,
868
872
  theme,