mixdog 0.9.3 → 0.9.5

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 (382) hide show
  1. package/README.md +112 -38
  2. package/package.json +10 -3
  3. package/scripts/bench/lead-review-tasks-r3.json +20 -0
  4. package/scripts/bench/lead-review-tasks.json +20 -0
  5. package/scripts/bench/r4-mixed-tasks.json +20 -0
  6. package/scripts/bench/r5-orchestrated-task.json +7 -0
  7. package/scripts/bench/review-tasks.json +20 -0
  8. package/scripts/bench/round-codex.json +114 -0
  9. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  10. package/scripts/bench/round-mixdog-lead.json +269 -0
  11. package/scripts/bench/round-mixdog.json +126 -0
  12. package/scripts/bench/round-r10-bigsample.json +679 -0
  13. package/scripts/bench/round-r11-codexalign.json +257 -0
  14. package/scripts/bench/round-r13-clientmeta.json +464 -0
  15. package/scripts/bench/round-r14-betafeatures.json +466 -0
  16. package/scripts/bench/round-r15-fulldefault.json +462 -0
  17. package/scripts/bench/round-r16-sessionid.json +466 -0
  18. package/scripts/bench/round-r17-wirebytes.json +456 -0
  19. package/scripts/bench/round-r18-prewarm.json +468 -0
  20. package/scripts/bench/round-r19-clean.json +472 -0
  21. package/scripts/bench/round-r20-prewarm-clean.json +475 -0
  22. package/scripts/bench/round-r21-delta-retry.json +473 -0
  23. package/scripts/bench/round-r22-full-probe.json +693 -0
  24. package/scripts/bench/round-r23-itemprobe.json +701 -0
  25. package/scripts/bench/round-r24-shapefix.json +677 -0
  26. package/scripts/bench/round-r25-serial.json +464 -0
  27. package/scripts/bench/round-r26-parallel3.json +671 -0
  28. package/scripts/bench/round-r27-parallel10.json +894 -0
  29. package/scripts/bench/round-r28-parallel10-stagger.json +882 -0
  30. package/scripts/bench/round-r29-parallel10-stagger166.json +886 -0
  31. package/scripts/bench/round-r30-instid.json +253 -0
  32. package/scripts/bench/round-r31-upgradeprobe.json +256 -0
  33. package/scripts/bench/round-r32-vs-codex-lead.json +254 -0
  34. package/scripts/bench/round-r33-vs-codex-codex.json +115 -0
  35. package/scripts/bench/round-r34-orchestrated.json +120 -0
  36. package/scripts/bench/round-r35-orchestrated-codex.json +61 -0
  37. package/scripts/bench/round-r36-orchestrated-capped.json +128 -0
  38. package/scripts/bench/round-r4-codex.json +114 -0
  39. package/scripts/bench/round-r4-mixed.json +225 -0
  40. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  41. package/scripts/bench/round-r6-codex.json +114 -0
  42. package/scripts/bench/round-r6-solo.json +257 -0
  43. package/scripts/bench/round-r7-full.json +254 -0
  44. package/scripts/bench/round-r8-fulldefault.json +255 -0
  45. package/scripts/bench-run.mjs +251 -32
  46. package/scripts/freevar-smoke.mjs +95 -0
  47. package/scripts/internal-comms-bench.mjs +3 -4
  48. package/scripts/internal-comms-smoke.mjs +10 -9
  49. package/scripts/model-catalog-audit.mjs +209 -0
  50. package/scripts/model-list-sanitize-test.mjs +37 -0
  51. package/scripts/mouse-probe.mjs +45 -0
  52. package/scripts/output-style-bench.mjs +13 -6
  53. package/scripts/output-style-smoke.mjs +4 -4
  54. package/scripts/provider-toolcall-test.mjs +7 -3
  55. package/scripts/recall-bench.mjs +76 -13
  56. package/scripts/recall-quality-cases.json +12 -0
  57. package/scripts/recall-usecase-cases.json +18 -0
  58. package/scripts/session-bench.mjs +152 -6
  59. package/scripts/tool-smoke.mjs +25 -65
  60. package/scripts/tui-render-smoke.mjs +90 -0
  61. package/scripts/webhook-smoke.mjs +208 -0
  62. package/src/agents/debugger/AGENT.md +4 -1
  63. package/src/agents/heavy-worker/AGENT.md +9 -8
  64. package/src/agents/maintainer/AGENT.md +4 -0
  65. package/src/agents/reviewer/AGENT.md +2 -1
  66. package/src/agents/scheduler-task/AGENT.md +2 -3
  67. package/src/agents/webhook-handler/AGENT.md +2 -3
  68. package/src/agents/worker/AGENT.md +10 -7
  69. package/src/app.mjs +12 -1
  70. package/src/headless-role.mjs +7 -1
  71. package/src/lib/rules-builder.cjs +4 -0
  72. package/src/mixdog-session-runtime.mjs +647 -2056
  73. package/src/output-styles/default.md +30 -9
  74. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  75. package/src/output-styles/minimal.md +8 -6
  76. package/src/output-styles/simple.md +21 -7
  77. package/src/rules/agent/00-common.md +6 -3
  78. package/src/rules/agent/30-explorer.md +16 -5
  79. package/src/rules/lead/01-general.md +5 -5
  80. package/src/rules/lead/lead-brief.md +15 -0
  81. package/src/rules/lead/lead-tool.md +6 -15
  82. package/src/rules/shared/01-tool.md +17 -21
  83. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +8 -3
  84. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  85. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  86. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  87. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  88. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  89. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  90. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  91. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +62 -20
  92. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  93. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  94. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +81 -1281
  95. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  96. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -3
  97. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  99. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  100. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  101. package/src/runtime/agent/orchestrator/providers/gemini.mjs +43 -1013
  102. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +17 -3
  103. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +105 -11
  104. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +356 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  108. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  109. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +40 -1143
  110. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +740 -0
  111. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  112. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +349 -2131
  113. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +143 -1002
  114. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +229 -0
  115. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  116. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +465 -0
  117. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  119. package/src/runtime/agent/orchestrator/providers/provider-catalog-cache.mjs +80 -0
  120. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  121. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  122. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  123. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  124. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  125. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  126. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  127. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  128. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +14 -2
  129. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  130. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -3
  131. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +275 -0
  132. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  133. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  134. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  135. package/src/runtime/agent/orchestrator/session/loop.mjs +278 -402
  136. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  137. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +7 -4
  138. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +12 -0
  139. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  140. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  141. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  142. package/src/runtime/agent/orchestrator/session/manager.mjs +166 -1087
  143. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  144. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  145. package/src/runtime/agent/orchestrator/stall-policy.mjs +20 -1
  146. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  147. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  148. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +35 -44
  149. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  152. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -92
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  155. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  156. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +28 -265
  157. package/src/runtime/agent/orchestrator/tools/builtin.mjs +0 -6
  158. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +57 -3
  159. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +10 -122
  161. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  163. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  164. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  165. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  166. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  167. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  168. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  169. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  170. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  171. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  172. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  173. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +0 -21
  174. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +9 -72
  175. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  176. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  177. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  178. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  179. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  180. package/src/runtime/channels/backends/discord.mjs +27 -318
  181. package/src/runtime/channels/backends/telegram.mjs +8 -12
  182. package/src/runtime/channels/index.mjs +247 -701
  183. package/src/runtime/channels/lib/backend-dispatch.mjs +46 -0
  184. package/src/runtime/channels/lib/config.mjs +37 -149
  185. package/src/runtime/channels/lib/event-pipeline.mjs +22 -5
  186. package/src/runtime/channels/lib/event-queue.mjs +78 -13
  187. package/src/runtime/channels/lib/inbound-routing.mjs +74 -0
  188. package/src/runtime/channels/lib/interaction-workflows.mjs +5 -113
  189. package/src/runtime/channels/lib/output-forwarder.mjs +1 -1
  190. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  191. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  192. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  193. package/src/runtime/channels/lib/scheduler.mjs +27 -113
  194. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  195. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  196. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  197. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  198. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  199. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  200. package/src/runtime/channels/lib/webhook/deliveries.mjs +313 -0
  201. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  202. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  203. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  204. package/src/runtime/channels/lib/webhook.mjs +43 -616
  205. package/src/runtime/channels/tool-defs.mjs +11 -130
  206. package/src/runtime/memory/index.mjs +210 -1948
  207. package/src/runtime/memory/lib/core-memory-store.mjs +5 -1
  208. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  209. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  210. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  211. package/src/runtime/memory/lib/ko-morph.mjs +195 -0
  212. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  213. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  214. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  215. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  216. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  217. package/src/runtime/memory/lib/memory-cycle2.mjs +24 -842
  218. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  219. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  220. package/src/runtime/memory/lib/memory-recall-store.mjs +69 -12
  221. package/src/runtime/memory/lib/memory-text-utils.mjs +46 -0
  222. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  223. package/src/runtime/memory/lib/query-handlers.mjs +802 -0
  224. package/src/runtime/memory/lib/recall-format.mjs +55 -0
  225. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  226. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  227. package/src/runtime/memory/tool-defs.mjs +5 -13
  228. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  229. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  230. package/src/runtime/search/lib/web-tools.mjs +24 -602
  231. package/src/runtime/shared/atomic-file.mjs +26 -1
  232. package/src/runtime/shared/config.mjs +14 -4
  233. package/src/runtime/shared/launcher-control.mjs +2 -2
  234. package/src/runtime/shared/markdown-frontmatter.mjs +19 -0
  235. package/src/runtime/shared/schedules-store.mjs +13 -3
  236. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  237. package/src/runtime/shared/tool-primitives.mjs +308 -0
  238. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  239. package/src/runtime/shared/tool-surface.mjs +80 -898
  240. package/src/runtime/shared/transcript-writer.mjs +23 -0
  241. package/src/runtime/shared/update-checker.mjs +7 -4
  242. package/src/session-runtime/config-helpers.mjs +119 -2
  243. package/src/session-runtime/config-lifecycle.mjs +232 -0
  244. package/src/session-runtime/cwd-plugins.mjs +226 -0
  245. package/src/session-runtime/mcp-glue.mjs +177 -0
  246. package/src/session-runtime/model-recency.mjs +111 -0
  247. package/src/session-runtime/native-search.mjs +247 -0
  248. package/src/session-runtime/output-styles.mjs +11 -9
  249. package/src/session-runtime/prewarm.mjs +142 -0
  250. package/src/session-runtime/provider-models.mjs +278 -0
  251. package/src/session-runtime/provider-usage.mjs +120 -0
  252. package/src/session-runtime/quick-model-rows.mjs +205 -0
  253. package/src/session-runtime/quick-search-models.mjs +47 -0
  254. package/src/session-runtime/session-hooks.mjs +93 -0
  255. package/src/session-runtime/settings-api.mjs +352 -0
  256. package/src/session-runtime/tool-catalog.mjs +29 -29
  257. package/src/session-runtime/tool-defs.mjs +84 -0
  258. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  259. package/src/session-runtime/workflow.mjs +1 -1
  260. package/src/standalone/agent-tool/helpers.mjs +237 -0
  261. package/src/standalone/agent-tool/notify.mjs +107 -0
  262. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  263. package/src/standalone/agent-tool/render.mjs +152 -0
  264. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  265. package/src/standalone/agent-tool.mjs +138 -669
  266. package/src/standalone/channel-admin.mjs +102 -90
  267. package/src/standalone/channel-worker.mjs +4 -7
  268. package/src/standalone/explore-tool.mjs +64 -14
  269. package/src/standalone/hook-bus/config.mjs +207 -0
  270. package/src/standalone/hook-bus/constants.mjs +90 -0
  271. package/src/standalone/hook-bus/handlers.mjs +481 -0
  272. package/src/standalone/hook-bus/payload.mjs +31 -0
  273. package/src/standalone/hook-bus/rules.mjs +77 -0
  274. package/src/standalone/hook-bus.mjs +77 -870
  275. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  276. package/src/standalone/opencode-go-login.mjs +5 -1
  277. package/src/standalone/provider-admin.mjs +1 -16
  278. package/src/standalone/usage-dashboard.mjs +3 -1
  279. package/src/tui/App.jsx +1059 -8110
  280. package/src/tui/app/app-format.mjs +213 -0
  281. package/src/tui/app/channel-pickers.mjs +508 -0
  282. package/src/tui/app/clipboard.mjs +67 -0
  283. package/src/tui/app/core-memory-picker.mjs +210 -0
  284. package/src/tui/app/extension-pickers.mjs +506 -0
  285. package/src/tui/app/input-parsers.mjs +193 -0
  286. package/src/tui/app/maintenance-pickers.mjs +356 -0
  287. package/src/tui/app/model-options.mjs +334 -0
  288. package/src/tui/app/model-picker.mjs +365 -0
  289. package/src/tui/app/onboarding-steps.mjs +400 -0
  290. package/src/tui/app/project-picker.mjs +247 -0
  291. package/src/tui/app/provider-setup-picker.mjs +580 -0
  292. package/src/tui/app/resume-picker.mjs +55 -0
  293. package/src/tui/app/route-pickers.mjs +419 -0
  294. package/src/tui/app/settings-picker.mjs +489 -0
  295. package/src/tui/app/slash-commands.mjs +101 -0
  296. package/src/tui/app/slash-dispatch.mjs +427 -0
  297. package/src/tui/app/text-layout.mjs +46 -0
  298. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  299. package/src/tui/app/transcript-window.mjs +677 -0
  300. package/src/tui/app/use-mouse-input.mjs +460 -0
  301. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  302. package/src/tui/app/use-transcript-scroll.mjs +512 -0
  303. package/src/tui/app/use-transcript-window.mjs +607 -0
  304. package/src/tui/components/ConfirmBar.jsx +10 -7
  305. package/src/tui/components/Picker.jsx +64 -15
  306. package/src/tui/components/PromptInput.jsx +33 -102
  307. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  308. package/src/tui/components/StatusLine.jsx +69 -15
  309. package/src/tui/components/TextEntryPanel.jsx +11 -0
  310. package/src/tui/components/ToolExecution.jsx +52 -594
  311. package/src/tui/components/TranscriptItem.jsx +105 -0
  312. package/src/tui/components/UsagePanel.jsx +18 -4
  313. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  314. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  315. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  316. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  317. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  318. package/src/tui/display-width.mjs +20 -3
  319. package/src/tui/dist/index.mjs +13553 -12384
  320. package/src/tui/engine/agent-job-feed.mjs +133 -0
  321. package/src/tui/engine/notification-plan.mjs +76 -0
  322. package/src/tui/engine/render-timing.mjs +17 -0
  323. package/src/tui/engine/tool-approval.mjs +94 -0
  324. package/src/tui/engine/tool-card-results.mjs +234 -0
  325. package/src/tui/engine/tool-result-status.mjs +135 -0
  326. package/src/tui/engine.mjs +170 -574
  327. package/src/tui/figures.mjs +5 -0
  328. package/src/tui/index.jsx +65 -1
  329. package/src/tui/input-editing.mjs +2 -2
  330. package/src/tui/markdown/format-token.mjs +4 -1
  331. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  332. package/src/tui/theme.mjs +6 -0
  333. package/src/ui/statusline-agents.mjs +213 -0
  334. package/src/ui/statusline-format.mjs +146 -0
  335. package/src/ui/statusline-segments.mjs +148 -0
  336. package/src/ui/statusline.mjs +77 -501
  337. package/src/ui/tool-card.mjs +0 -1
  338. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  339. package/src/workflows/default/WORKFLOW.md +16 -18
  340. package/src/workflows/sequential/WORKFLOW.md +16 -18
  341. package/vendor/ink/build/display-width.js +19 -3
  342. package/vendor/ink/build/ink.js +112 -7
  343. package/vendor/ink/build/log-update.js +17 -3
  344. package/vendor/ink/build/wrap-text.js +125 -0
  345. package/scripts/_test-folder-dialog.mjs +0 -30
  346. package/scripts/fix-brief-fn.mjs +0 -35
  347. package/scripts/fix-format-tool-surface.mjs +0 -24
  348. package/scripts/fix-tool-exec-visible.mjs +0 -42
  349. package/scripts/patch-agent-brief.mjs +0 -48
  350. package/scripts/patch-app.mjs +0 -21
  351. package/scripts/patch-app2.mjs +0 -18
  352. package/scripts/patch-dist-brief.mjs +0 -96
  353. package/scripts/patch-tool-exec.mjs +0 -70
  354. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  355. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  356. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  357. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  358. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  359. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +0 -162
  360. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  361. package/src/runtime/channels/lib/holidays.mjs +0 -138
  362. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  363. package/src/runtime/shared/task-notification-envelope.test.mjs +0 -107
  364. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  365. package/src/standalone/agent-task-status.test.mjs +0 -76
  366. package/src/tui/components/tool-output-format.test.mjs +0 -399
  367. package/src/tui/display-width.test.mjs +0 -35
  368. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  369. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  370. package/src/tui/input-editing.selection.test.mjs +0 -75
  371. package/src/tui/markdown/format-token.test.mjs +0 -354
  372. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  373. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  374. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  375. package/src/tui/paste-fix.test.mjs +0 -119
  376. package/src/tui/prompt-history-store.test.mjs +0 -52
  377. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  378. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  379. package/src/ui/markdown.test.mjs +0 -70
  380. package/src/ui/statusline-context-label.test.mjs +0 -15
  381. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  382. package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
@@ -0,0 +1,505 @@
1
+ /**
2
+ * gemini-stream.mjs — Gemini stream consumption (REST + SDK) and stream guards.
3
+ *
4
+ * Extracted from gemini.mjs. Owns chunk aggregation, completion assertions,
5
+ * timeout/truncation error shapes and the text leak guard that recovers
6
+ * tool calls emitted as plain text. gemini.mjs imports the consumer entry
7
+ * points; parseToolCalls/emitGeminiToolCalls stay in gemini.mjs and are
8
+ * imported back (function-level, no init-time cycle).
9
+ */
10
+ import {
11
+ PROVIDER_FIRST_BYTE_TIMEOUT_MS,
12
+ PROVIDER_MAX_BEFORE_WARN_MS,
13
+ PROVIDER_SSE_IDLE_TIMEOUT_MS,
14
+ PROVIDER_SSE_IDLE_WATCHDOG_ENABLED,
15
+ providerTimeoutError,
16
+ resolveTimeoutMs,
17
+ } from '../stall-policy.mjs';
18
+ import { scanLeakedToolCalls } from './anthropic-leaked-toolcall.mjs';
19
+ import { traceHash, stableTraceStringify } from './trace-utils.mjs';
20
+ import { parseToolCalls, emitGeminiToolCalls, collectGeminiGroundingSources } from './gemini.mjs';
21
+
22
+ export const GEMINI_FIRST_BYTE_TIMEOUT_MS = resolveTimeoutMs(
23
+ 'MIXDOG_GEMINI_FIRST_BYTE_TIMEOUT_MS',
24
+ PROVIDER_FIRST_BYTE_TIMEOUT_MS,
25
+ { minMs: 30_000, maxMs: PROVIDER_MAX_BEFORE_WARN_MS },
26
+ );
27
+
28
+ export function geminiTimeoutError(label, timeoutMs) {
29
+ const err = providerTimeoutError(label, timeoutMs);
30
+ err.name = 'GeminiTimeoutError';
31
+ err.code = 'EGEMINITIMEOUT';
32
+ return err;
33
+ }
34
+
35
+ export function geminiTruncatedStreamError(message) {
36
+ return Object.assign(
37
+ new Error(message),
38
+ { name: 'TruncatedStreamError', code: 'TRUNCATED_STREAM', truncatedStream: true },
39
+ );
40
+ }
41
+
42
+ /**
43
+ * Aggregate streamed GenerateContentResponse chunks into one response object
44
+ * (same shape as a non-streaming generateContent JSON body).
45
+ * Mirrors @google/generative-ai aggregateResponses().
46
+ */
47
+ export function aggregateGeminiStreamChunks(responses) {
48
+ const lastResponse = responses[responses.length - 1];
49
+ const aggregatedResponse = {
50
+ promptFeedback: lastResponse?.promptFeedback,
51
+ };
52
+ for (const response of responses) {
53
+ if (response?.candidates) {
54
+ let candidateIndex = 0;
55
+ for (const candidate of response.candidates) {
56
+ if (!aggregatedResponse.candidates) aggregatedResponse.candidates = [];
57
+ if (!aggregatedResponse.candidates[candidateIndex]) {
58
+ aggregatedResponse.candidates[candidateIndex] = { index: candidateIndex };
59
+ }
60
+ const aggCand = aggregatedResponse.candidates[candidateIndex];
61
+ aggCand.citationMetadata = candidate.citationMetadata;
62
+ aggCand.groundingMetadata = candidate.groundingMetadata;
63
+ aggCand.finishReason = candidate.finishReason;
64
+ aggCand.finishMessage = candidate.finishMessage;
65
+ aggCand.safetyRatings = candidate.safetyRatings;
66
+ if (candidate.content?.parts) {
67
+ if (!aggCand.content) {
68
+ aggCand.content = {
69
+ role: candidate.content.role || 'user',
70
+ parts: [],
71
+ };
72
+ }
73
+ for (const part of candidate.content.parts) {
74
+ const newPart = {};
75
+ if (part.text) newPart.text = part.text;
76
+ if (part.functionCall) newPart.functionCall = part.functionCall;
77
+ if (part.thoughtSignature) newPart.thoughtSignature = part.thoughtSignature;
78
+ if (part.thought_signature) newPart.thought_signature = part.thought_signature;
79
+ if (part.executableCode) newPart.executableCode = part.executableCode;
80
+ if (part.codeExecutionResult) newPart.codeExecutionResult = part.codeExecutionResult;
81
+ if (Object.keys(newPart).length === 0) newPart.text = '';
82
+ aggCand.content.parts.push(newPart);
83
+ }
84
+ }
85
+ candidateIndex++;
86
+ }
87
+ }
88
+ if (response?.usageMetadata) aggregatedResponse.usageMetadata = response.usageMetadata;
89
+ }
90
+ return aggregatedResponse;
91
+ }
92
+
93
+ export function assertGeminiStreamCompleted({ sawStreamChunk, finishReason, label }) {
94
+ if (!sawStreamChunk) {
95
+ throw geminiTruncatedStreamError(`${label} truncated: empty stream`);
96
+ }
97
+ if (!finishReason) {
98
+ throw geminiTruncatedStreamError(`${label} truncated: no finishReason`);
99
+ }
100
+ }
101
+
102
+ // Concatenate the text parts of a single streamed Gemini chunk. Used to feed
103
+ // the gateway live-text relay (onTextDelta) with the incremental text payload
104
+ // as each SSE/SDK chunk arrives. Returns '' for tool-call / thought-only /
105
+ // malformed chunks so the caller can skip empty emits.
106
+ export function geminiChunkText(chunk) {
107
+ const parts = chunk?.candidates?.[0]?.content?.parts;
108
+ if (!Array.isArray(parts)) return '';
109
+ let text = '';
110
+ for (const p of parts) {
111
+ if (p && typeof p.text === 'string') text += p.text;
112
+ }
113
+ return text;
114
+ }
115
+
116
+ export function relayGeminiStreamText(t, { onTextDelta, textLeakGuard }) {
117
+ if (!t) return;
118
+ if (textLeakGuard) textLeakGuard.feedText(t);
119
+ else if (onTextDelta) { try { onTextDelta(t); } catch {} }
120
+ }
121
+
122
+ /**
123
+ * Rolling scanner for tool calls leaked as plain XML/antml tags inside Gemini
124
+ * `part.text` streams. Mirrors the Anthropic OAuth guard: suppress tags from
125
+ * visible text, synthesize known-tool calls, dispatch via onToolCall.
126
+ */
127
+ export function createGeminiTextLeakGuard({ knownToolNames, onTextDelta, onToolCall, onStreamDelta }) {
128
+ const _knownTools = knownToolNames instanceof Set
129
+ ? knownToolNames
130
+ : new Set(Array.isArray(knownToolNames) ? knownToolNames : []);
131
+ const _enabled = _knownTools.size > 0;
132
+ const _isKnownTool = (name) => _knownTools.has(name);
133
+ let leakBuffer = '';
134
+ const leakedCalls = [];
135
+ const dispatchedFingerprints = new Set();
136
+
137
+ const toolCallFingerprint = (name, args) => {
138
+ let a = args;
139
+ if (a === null || typeof a !== 'object' || Array.isArray(a)) a = {};
140
+ return traceHash(stableTraceStringify({ name: name || '', args: a }));
141
+ };
142
+
143
+ const dispatchLeakedCall = (recovered) => {
144
+ let args = recovered?.arguments;
145
+ if (args === null || typeof args !== 'object' || Array.isArray(args)) args = {};
146
+ const fp = toolCallFingerprint(recovered.name, args);
147
+ if (dispatchedFingerprints.has(fp)) return;
148
+ dispatchedFingerprints.add(fp);
149
+ const idHash = traceHash(stableTraceStringify({
150
+ name: recovered.name,
151
+ args,
152
+ leak: true,
153
+ })).slice(0, 16);
154
+ const call = {
155
+ id: `gemini_leaked_${idHash}`,
156
+ name: recovered.name,
157
+ arguments: args,
158
+ };
159
+ leakedCalls.push(call);
160
+ try { onToolCall?.(call); } catch {}
161
+ try { onStreamDelta?.(); } catch {}
162
+ };
163
+
164
+ const pumpLeakBuffer = (final) => {
165
+ if (!_enabled) return;
166
+ if (!leakBuffer && !final) return;
167
+ const { emit, calls, rest } = scanLeakedToolCalls(leakBuffer, { isKnownTool: _isKnownTool, final });
168
+ leakBuffer = rest;
169
+ if (emit && onTextDelta) {
170
+ try { onTextDelta(emit); } catch {}
171
+ }
172
+ for (const c of calls) dispatchLeakedCall(c);
173
+ };
174
+
175
+ return {
176
+ get enabled() { return _enabled; },
177
+ feedText(text) {
178
+ if (!text) return;
179
+ if (!_enabled) {
180
+ try { onTextDelta?.(text); } catch {}
181
+ return;
182
+ }
183
+ leakBuffer += text;
184
+ pumpLeakBuffer(false);
185
+ },
186
+ finalize() {
187
+ pumpLeakBuffer(true);
188
+ },
189
+ scrubAssistantText(raw) {
190
+ if (!raw) return '';
191
+ if (!_enabled) return raw;
192
+ const { emit, calls, rest } = scanLeakedToolCalls(raw, { isKnownTool: _isKnownTool, final: true });
193
+ for (const c of calls) dispatchLeakedCall(c);
194
+ return emit + rest;
195
+ },
196
+ filterNativeToolCalls(nativeCalls) {
197
+ if (!_enabled || !nativeCalls?.length) return nativeCalls;
198
+ const kept = [];
199
+ for (const call of nativeCalls) {
200
+ const fp = toolCallFingerprint(call?.name, call?.arguments);
201
+ if (dispatchedFingerprints.has(fp)) continue;
202
+ dispatchedFingerprints.add(fp);
203
+ kept.push(call);
204
+ }
205
+ return kept.length ? kept : undefined;
206
+ },
207
+ getLeakedToolCalls() {
208
+ return leakedCalls.length ? [...leakedCalls] : [];
209
+ },
210
+ };
211
+ }
212
+
213
+ export async function consumeGeminiRestStreamResponse(response, { signal, onStreamDelta, onTextDelta, textLeakGuard, label }) {
214
+ if (!response?.body) throw new Error(`${label}: missing response body`);
215
+ const reader = response.body.getReader();
216
+ const decoder = new TextDecoder();
217
+ let buffer = '';
218
+ const allChunks = [];
219
+ let sawStreamChunk = false;
220
+ let idleTimedOut = false;
221
+ let idleTimer = null;
222
+ let idleReject = null;
223
+
224
+ let firstByteTimer = setTimeout(() => {
225
+ try { reader.cancel('first byte timeout'); } catch {}
226
+ if (idleReject) {
227
+ const e = geminiTimeoutError(`${label} first byte`, GEMINI_FIRST_BYTE_TIMEOUT_MS);
228
+ const r = idleReject; idleReject = null; r(e);
229
+ }
230
+ }, GEMINI_FIRST_BYTE_TIMEOUT_MS);
231
+ if (firstByteTimer.unref) firstByteTimer.unref();
232
+
233
+ const clearFirstByteTimer = () => {
234
+ if (firstByteTimer) {
235
+ clearTimeout(firstByteTimer);
236
+ firstByteTimer = null;
237
+ }
238
+ };
239
+
240
+ const resetIdleTimer = () => {
241
+ if (!PROVIDER_SSE_IDLE_WATCHDOG_ENABLED) return;
242
+ if (idleTimer) clearTimeout(idleTimer);
243
+ idleTimer = setTimeout(() => {
244
+ idleTimedOut = true;
245
+ try { reader.cancel('SSE idle timeout'); } catch {}
246
+ if (idleReject) {
247
+ const e = geminiTimeoutError(`${label} SSE idle`, PROVIDER_SSE_IDLE_TIMEOUT_MS);
248
+ const r = idleReject; idleReject = null; r(e);
249
+ }
250
+ }, PROVIDER_SSE_IDLE_TIMEOUT_MS);
251
+ if (idleTimer.unref) idleTimer.unref();
252
+ };
253
+
254
+ const onAbort = () => {
255
+ try {
256
+ const c = reader.cancel('aborted');
257
+ if (c && typeof c.catch === 'function') c.catch(() => {});
258
+ } catch {}
259
+ };
260
+
261
+ if (signal) {
262
+ if (signal.aborted) {
263
+ const reason = signal.reason;
264
+ throw reason instanceof Error ? reason : new Error(`${label} aborted`);
265
+ }
266
+ signal.addEventListener('abort', onAbort, { once: true });
267
+ }
268
+
269
+ try {
270
+ resetIdleTimer();
271
+ while (true) {
272
+ let chunk;
273
+ try {
274
+ chunk = await new Promise((resolve, reject) => {
275
+ idleReject = reject;
276
+ reader.read().then(resolve, reject);
277
+ });
278
+ } catch (err) {
279
+ if (idleTimedOut) {
280
+ throw geminiTimeoutError(`${label} SSE idle`, PROVIDER_SSE_IDLE_TIMEOUT_MS);
281
+ }
282
+ if (signal?.aborted) {
283
+ const reason = signal.reason;
284
+ throw reason instanceof Error ? reason : new Error(`${label} aborted`);
285
+ }
286
+ throw err;
287
+ } finally {
288
+ idleReject = null;
289
+ }
290
+ const { done, value } = chunk;
291
+ if (done) break;
292
+ resetIdleTimer();
293
+ buffer += decoder.decode(value, { stream: true });
294
+ let lineEnd;
295
+ while ((lineEnd = buffer.indexOf('\n')) >= 0) {
296
+ let line = buffer.slice(0, lineEnd);
297
+ buffer = buffer.slice(lineEnd + 1);
298
+ line = line.replace(/\r$/, '');
299
+ if (!line.startsWith('data: ')) continue;
300
+ const data = line.slice(6).trim();
301
+ if (!data || data === '[DONE]') continue;
302
+ let parsed;
303
+ try { parsed = JSON.parse(data); } catch { continue; }
304
+ if (!sawStreamChunk) {
305
+ sawStreamChunk = true;
306
+ clearFirstByteTimer();
307
+ }
308
+ allChunks.push(parsed);
309
+ try { onStreamDelta?.(); } catch {}
310
+ if (onTextDelta || textLeakGuard) {
311
+ const t = geminiChunkText(parsed);
312
+ relayGeminiStreamText(t, { onTextDelta, textLeakGuard });
313
+ }
314
+ }
315
+ }
316
+ if (buffer.trim()) {
317
+ const line = buffer.trim().replace(/\r$/, '');
318
+ if (line.startsWith('data: ')) {
319
+ const data = line.slice(6).trim();
320
+ if (data && data !== '[DONE]') {
321
+ try {
322
+ const parsed = JSON.parse(data);
323
+ if (!sawStreamChunk) {
324
+ sawStreamChunk = true;
325
+ clearFirstByteTimer();
326
+ }
327
+ allChunks.push(parsed);
328
+ try { onStreamDelta?.(); } catch {}
329
+ if (onTextDelta || textLeakGuard) {
330
+ const t = geminiChunkText(parsed);
331
+ relayGeminiStreamText(t, { onTextDelta, textLeakGuard });
332
+ }
333
+ } catch { /* skip malformed tail */ }
334
+ }
335
+ }
336
+ }
337
+ } finally {
338
+ clearFirstByteTimer();
339
+ if (idleTimer) clearTimeout(idleTimer);
340
+ if (signal) signal.removeEventListener('abort', onAbort);
341
+ try { reader.releaseLock(); } catch {}
342
+ try { textLeakGuard?.finalize(); } catch {}
343
+ }
344
+
345
+ const aggregated = aggregateGeminiStreamChunks(allChunks);
346
+ const finishReason = aggregated.candidates?.[0]?.finishReason || null;
347
+ assertGeminiStreamCompleted({ sawStreamChunk, finishReason, label });
348
+ return aggregated;
349
+ }
350
+
351
+ export async function consumeGeminiSdkStream(streamResult, { signal, onStreamDelta, onTextDelta, textLeakGuard, label }) {
352
+ let sawStreamChunk = false;
353
+ let idleTimedOut = false;
354
+ let idleTimer = null;
355
+ let firstByteReject = null;
356
+ let firstByteTimer = null;
357
+ let inFlightReject = null;
358
+
359
+ const armFirstByteTimer = () => {
360
+ if (firstByteTimer) clearTimeout(firstByteTimer);
361
+ firstByteTimer = setTimeout(() => {
362
+ if (firstByteReject) {
363
+ const e = geminiTimeoutError(`${label} first byte`, GEMINI_FIRST_BYTE_TIMEOUT_MS);
364
+ const r = firstByteReject; firstByteReject = null; r(e);
365
+ }
366
+ }, GEMINI_FIRST_BYTE_TIMEOUT_MS);
367
+ if (firstByteTimer.unref) firstByteTimer.unref();
368
+ };
369
+
370
+ const clearFirstByteTimer = () => {
371
+ if (firstByteTimer) {
372
+ clearTimeout(firstByteTimer);
373
+ firstByteTimer = null;
374
+ }
375
+ firstByteReject = null;
376
+ };
377
+
378
+ const resetIdleTimer = () => {
379
+ if (!PROVIDER_SSE_IDLE_WATCHDOG_ENABLED) return;
380
+ if (idleTimer) clearTimeout(idleTimer);
381
+ idleTimer = setTimeout(() => {
382
+ idleTimedOut = true;
383
+ if (inFlightReject) {
384
+ const e = geminiTimeoutError(`${label} SSE idle`, PROVIDER_SSE_IDLE_TIMEOUT_MS);
385
+ const r = inFlightReject; inFlightReject = null; r(e);
386
+ }
387
+ }, PROVIDER_SSE_IDLE_TIMEOUT_MS);
388
+ if (idleTimer.unref) idleTimer.unref();
389
+ };
390
+
391
+ if (signal?.aborted) {
392
+ const reason = signal.reason;
393
+ throw reason instanceof Error ? reason : new Error(`${label} aborted`);
394
+ }
395
+
396
+ const iterator = streamResult.stream[Symbol.asyncIterator]();
397
+
398
+ // Wire the abort signal to actually CANCEL iteration (mirror of the REST
399
+ // consumer's onAbort -> reader.cancel). Without this, a parent / client /
400
+ // gateway abort that fires AFTER the first byte — with the SSE idle
401
+ // watchdog off by default — would leave iterator.next() hanging: the loop
402
+ // below only reads `signal` for error translation, never to interrupt the
403
+ // pending read. Rejecting the in-flight promise and returning the iterator
404
+ // releases it promptly even if the SDK is slow to propagate the underlying
405
+ // request abort.
406
+ let onSignalAbort = null;
407
+ if (signal) {
408
+ onSignalAbort = () => {
409
+ const reason = signal.reason;
410
+ const err = reason instanceof Error ? reason : new Error(`${label} aborted`);
411
+ if (inFlightReject) {
412
+ const r = inFlightReject;
413
+ inFlightReject = null;
414
+ firstByteReject = null;
415
+ r(err);
416
+ }
417
+ try {
418
+ const ret = iterator.return?.();
419
+ if (ret && typeof ret.catch === 'function') ret.catch(() => {});
420
+ } catch {}
421
+ };
422
+ signal.addEventListener('abort', onSignalAbort, { once: true });
423
+ }
424
+
425
+ try {
426
+ armFirstByteTimer();
427
+ resetIdleTimer();
428
+ while (true) {
429
+ if (idleTimedOut) {
430
+ throw geminiTimeoutError(`${label} SSE idle`, PROVIDER_SSE_IDLE_TIMEOUT_MS);
431
+ }
432
+ let step;
433
+ try {
434
+ step = await new Promise((resolve, reject) => {
435
+ inFlightReject = reject;
436
+ if (!sawStreamChunk) firstByteReject = reject;
437
+ iterator.next().then(
438
+ (value) => {
439
+ inFlightReject = null;
440
+ firstByteReject = null;
441
+ resolve(value);
442
+ },
443
+ (err) => {
444
+ inFlightReject = null;
445
+ firstByteReject = null;
446
+ reject(err);
447
+ },
448
+ );
449
+ });
450
+ } catch (err) {
451
+ if (idleTimedOut) {
452
+ throw geminiTimeoutError(`${label} SSE idle`, PROVIDER_SSE_IDLE_TIMEOUT_MS);
453
+ }
454
+ if (signal?.aborted) {
455
+ const reason = signal.reason;
456
+ throw reason instanceof Error ? reason : new Error(`${label} aborted`);
457
+ }
458
+ throw err;
459
+ }
460
+ if (step.done) break;
461
+ if (!sawStreamChunk) {
462
+ sawStreamChunk = true;
463
+ clearFirstByteTimer();
464
+ }
465
+ resetIdleTimer();
466
+ try { onStreamDelta?.(); } catch {}
467
+ if (onTextDelta || textLeakGuard) {
468
+ const t = geminiChunkText(step.value);
469
+ relayGeminiStreamText(t, { onTextDelta, textLeakGuard });
470
+ }
471
+ }
472
+ if (idleTimedOut) {
473
+ throw geminiTimeoutError(`${label} SSE idle`, PROVIDER_SSE_IDLE_TIMEOUT_MS);
474
+ }
475
+ } catch (err) {
476
+ clearFirstByteTimer();
477
+ if (signal?.aborted) {
478
+ const reason = signal.reason;
479
+ throw reason instanceof Error ? reason : new Error(`${label} aborted`);
480
+ }
481
+ throw err;
482
+ } finally {
483
+ clearFirstByteTimer();
484
+ if (idleTimer) clearTimeout(idleTimer);
485
+ if (signal && onSignalAbort) {
486
+ try { signal.removeEventListener('abort', onSignalAbort); } catch {}
487
+ }
488
+ try { textLeakGuard?.finalize(); } catch {}
489
+ }
490
+
491
+ let response;
492
+ try {
493
+ response = await streamResult.response;
494
+ } catch (err) {
495
+ if (signal?.aborted) {
496
+ const reason = signal.reason;
497
+ throw reason instanceof Error ? reason : new Error(`${label} aborted`);
498
+ }
499
+ throw err;
500
+ }
501
+ const raw = response?.candidates ? response : (response?.response || response);
502
+ const finishReason = raw?.candidates?.[0]?.finishReason || null;
503
+ assertGeminiStreamCompleted({ sawStreamChunk, finishReason, label });
504
+ return raw;
505
+ }