mixdog 0.9.2 → 0.9.4

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 (417) hide show
  1. package/package.json +8 -3
  2. package/scripts/anthropic-maxtokens-test.mjs +119 -0
  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/review-tasks.json +20 -0
  7. package/scripts/bench/round-codex.json +114 -0
  8. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  9. package/scripts/bench/round-mixdog-lead.json +269 -0
  10. package/scripts/bench/round-mixdog.json +126 -0
  11. package/scripts/bench/round-r10-bigsample.json +679 -0
  12. package/scripts/bench/round-r11-codexalign.json +257 -0
  13. package/scripts/bench/round-r4-codex.json +114 -0
  14. package/scripts/bench/round-r4-mixed.json +225 -0
  15. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  16. package/scripts/bench/round-r6-codex.json +114 -0
  17. package/scripts/bench/round-r6-solo.json +257 -0
  18. package/scripts/bench/round-r7-full.json +254 -0
  19. package/scripts/bench/round-r8-fulldefault.json +255 -0
  20. package/scripts/bench-run.mjs +215 -29
  21. package/scripts/build-tui.mjs +13 -1
  22. package/scripts/explore-bench.mjs +124 -0
  23. package/scripts/freevar-smoke.mjs +95 -0
  24. package/scripts/hook-bus-test.mjs +191 -0
  25. package/scripts/internal-comms-bench.mjs +1 -0
  26. package/scripts/internal-comms-smoke.mjs +10 -9
  27. package/scripts/mouse-probe.mjs +45 -0
  28. package/scripts/output-style-bench.mjs +13 -6
  29. package/scripts/output-style-smoke.mjs +4 -4
  30. package/scripts/path-suffix-test.mjs +57 -0
  31. package/scripts/provider-toolcall-test.mjs +7 -3
  32. package/scripts/recall-bench.mjs +207 -0
  33. package/scripts/recall-usecase-cases.json +18 -0
  34. package/scripts/recall-usecase-probe.json +6 -0
  35. package/scripts/session-bench.mjs +152 -6
  36. package/scripts/tool-smoke.mjs +30 -67
  37. package/scripts/tui-render-smoke.mjs +90 -0
  38. package/scripts/webhook-smoke.mjs +208 -0
  39. package/src/agents/debugger/AGENT.md +5 -2
  40. package/src/agents/heavy-worker/AGENT.md +21 -11
  41. package/src/agents/maintainer/AGENT.md +4 -0
  42. package/src/agents/reviewer/AGENT.md +3 -2
  43. package/src/agents/worker/AGENT.md +21 -11
  44. package/src/lib/rules-builder.cjs +4 -0
  45. package/src/mixdog-session-runtime.mjs +933 -3731
  46. package/src/output-styles/default.md +34 -9
  47. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  48. package/src/output-styles/minimal.md +4 -1
  49. package/src/output-styles/simple.md +22 -7
  50. package/src/repl.mjs +5 -5
  51. package/src/rules/agent/00-common.md +2 -0
  52. package/src/rules/agent/30-explorer.md +8 -11
  53. package/src/rules/lead/lead-brief.md +12 -0
  54. package/src/rules/lead/lead-tool.md +2 -9
  55. package/src/rules/shared/01-tool.md +11 -5
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  57. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  58. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  59. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  60. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  61. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  62. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  63. package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
  64. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
  66. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
  70. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  71. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
  72. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
  73. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  74. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  75. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  76. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  77. package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
  78. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
  80. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
  81. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
  82. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
  83. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  84. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
  85. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
  92. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
  94. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
  96. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  98. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
  99. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
  100. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  101. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  102. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  103. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  107. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  108. package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
  109. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
  110. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  111. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
  112. package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
  113. package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
  114. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
  115. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
  116. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  117. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
  118. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
  119. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  120. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
  121. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  122. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
  123. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
  124. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
  125. package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
  126. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  127. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
  128. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
  129. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
  130. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
  131. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  132. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  133. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
  136. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  137. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  138. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
  139. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  141. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
  142. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
  143. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  145. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
  146. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
  148. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  149. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
  152. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
  155. package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
  156. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
  157. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
  158. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
  159. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
  161. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  163. package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
  164. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
  165. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
  166. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
  167. package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
  168. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
  169. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
  170. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  171. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
  172. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  173. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
  174. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  175. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  176. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  177. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  178. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  179. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  180. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  181. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  182. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  183. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  184. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
  185. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
  186. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  187. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
  188. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  189. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  190. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  191. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  192. package/src/runtime/channels/backends/discord.mjs +12 -292
  193. package/src/runtime/channels/index.mjs +241 -894
  194. package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
  195. package/src/runtime/channels/lib/boot-profile.mjs +23 -0
  196. package/src/runtime/channels/lib/crash-log.mjs +106 -0
  197. package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
  198. package/src/runtime/channels/lib/event-queue.mjs +63 -4
  199. package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
  200. package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
  201. package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
  202. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  203. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  204. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  205. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  206. package/src/runtime/channels/lib/telegram-format.mjs +19 -22
  207. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  208. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  209. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  210. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  211. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  212. package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
  213. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  214. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  215. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  216. package/src/runtime/channels/lib/webhook.mjs +36 -570
  217. package/src/runtime/channels/lib/whisper-language.mjs +42 -0
  218. package/src/runtime/channels/tool-defs.mjs +11 -130
  219. package/src/runtime/memory/index.mjs +258 -2050
  220. package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
  221. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  222. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  223. package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
  224. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  225. package/src/runtime/memory/lib/http-wire.mjs +57 -0
  226. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  227. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  228. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  229. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  230. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  231. package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
  232. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  233. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  234. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
  235. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
  236. package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
  237. package/src/runtime/memory/lib/memory.mjs +20 -0
  238. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  239. package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
  240. package/src/runtime/memory/lib/query-handlers.mjs +780 -0
  241. package/src/runtime/memory/lib/recall-format.mjs +238 -0
  242. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  243. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  244. package/src/runtime/memory/tool-defs.mjs +6 -14
  245. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  246. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  247. package/src/runtime/search/lib/web-tools.mjs +24 -602
  248. package/src/runtime/shared/abort-controller.mjs +1 -1
  249. package/src/runtime/shared/atomic-file.mjs +26 -1
  250. package/src/runtime/shared/background-tasks.mjs +2 -3
  251. package/src/runtime/shared/buffered-appender.mjs +149 -0
  252. package/src/runtime/shared/launcher-control.mjs +2 -2
  253. package/src/runtime/shared/task-notification-envelope.mjs +98 -0
  254. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  255. package/src/runtime/shared/tool-primitives.mjs +308 -0
  256. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  257. package/src/runtime/shared/tool-surface.mjs +80 -898
  258. package/src/runtime/shared/transcript-writer.mjs +52 -2
  259. package/src/runtime/shared/update-checker.mjs +7 -4
  260. package/src/session-runtime/config-helpers.mjs +291 -0
  261. package/src/session-runtime/config-lifecycle.mjs +232 -0
  262. package/src/session-runtime/cwd-plugins.mjs +226 -0
  263. package/src/session-runtime/effort.mjs +128 -0
  264. package/src/session-runtime/fs-utils.mjs +10 -0
  265. package/src/session-runtime/mcp-glue.mjs +177 -0
  266. package/src/session-runtime/model-capabilities.mjs +130 -0
  267. package/src/session-runtime/model-recency.mjs +111 -0
  268. package/src/session-runtime/native-search.mjs +247 -0
  269. package/src/session-runtime/output-styles.mjs +126 -0
  270. package/src/session-runtime/plugin-mcp.mjs +114 -0
  271. package/src/session-runtime/prewarm.mjs +142 -0
  272. package/src/session-runtime/provider-models.mjs +278 -0
  273. package/src/session-runtime/provider-usage.mjs +120 -0
  274. package/src/session-runtime/quick-model-rows.mjs +170 -0
  275. package/src/session-runtime/quick-search-models.mjs +46 -0
  276. package/src/session-runtime/session-hooks.mjs +93 -0
  277. package/src/session-runtime/session-text.mjs +100 -0
  278. package/src/session-runtime/settings-api.mjs +319 -0
  279. package/src/session-runtime/statusline-route.mjs +35 -0
  280. package/src/session-runtime/tool-catalog.mjs +720 -0
  281. package/src/session-runtime/tool-defs.mjs +84 -0
  282. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  283. package/src/session-runtime/workflow.mjs +358 -0
  284. package/src/standalone/agent-tool/helpers.mjs +237 -0
  285. package/src/standalone/agent-tool/notify.mjs +107 -0
  286. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  287. package/src/standalone/agent-tool/render.mjs +152 -0
  288. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  289. package/src/standalone/agent-tool.mjs +155 -677
  290. package/src/standalone/channel-worker.mjs +7 -9
  291. package/src/standalone/explore-tool.mjs +40 -12
  292. package/src/standalone/hook-bus/config.mjs +207 -0
  293. package/src/standalone/hook-bus/constants.mjs +90 -0
  294. package/src/standalone/hook-bus/handlers.mjs +481 -0
  295. package/src/standalone/hook-bus/payload.mjs +31 -0
  296. package/src/standalone/hook-bus/rules.mjs +77 -0
  297. package/src/standalone/hook-bus.mjs +110 -746
  298. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  299. package/src/standalone/opencode-go-login.mjs +125 -0
  300. package/src/standalone/provider-admin.mjs +15 -19
  301. package/src/standalone/usage-dashboard.mjs +3 -1
  302. package/src/tui/App.jsx +1163 -7571
  303. package/src/tui/app/app-format.mjs +206 -0
  304. package/src/tui/app/channel-pickers.mjs +510 -0
  305. package/src/tui/app/clipboard.mjs +67 -0
  306. package/src/tui/app/core-memory-picker.mjs +210 -0
  307. package/src/tui/app/extension-pickers.mjs +506 -0
  308. package/src/tui/app/input-parsers.mjs +193 -0
  309. package/src/tui/app/maintenance-pickers.mjs +324 -0
  310. package/src/tui/app/model-options.mjs +330 -0
  311. package/src/tui/app/model-picker.mjs +365 -0
  312. package/src/tui/app/onboarding-steps.mjs +400 -0
  313. package/src/tui/app/project-picker.mjs +247 -0
  314. package/src/tui/app/provider-setup-picker.mjs +580 -0
  315. package/src/tui/app/resume-picker.mjs +55 -0
  316. package/src/tui/app/route-pickers.mjs +419 -0
  317. package/src/tui/app/settings-picker.mjs +490 -0
  318. package/src/tui/app/slash-commands.mjs +101 -0
  319. package/src/tui/app/slash-dispatch.mjs +427 -0
  320. package/src/tui/app/text-layout.mjs +46 -0
  321. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  322. package/src/tui/app/transcript-window.mjs +671 -0
  323. package/src/tui/app/use-mouse-input.mjs +460 -0
  324. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  325. package/src/tui/app/use-transcript-scroll.mjs +510 -0
  326. package/src/tui/app/use-transcript-window.mjs +589 -0
  327. package/src/tui/components/ConfirmBar.jsx +1 -1
  328. package/src/tui/components/Picker.jsx +32 -4
  329. package/src/tui/components/PromptInput.jsx +259 -80
  330. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  331. package/src/tui/components/StatusLine.jsx +63 -12
  332. package/src/tui/components/TextEntryPanel.jsx +11 -0
  333. package/src/tui/components/ToolExecution.jsx +56 -588
  334. package/src/tui/components/TranscriptItem.jsx +105 -0
  335. package/src/tui/components/UsagePanel.jsx +18 -4
  336. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  337. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  338. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  339. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  340. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  341. package/src/tui/components/tool-output-format.mjs +2 -2
  342. package/src/tui/display-width.mjs +20 -3
  343. package/src/tui/dist/index.mjs +18034 -17188
  344. package/src/tui/engine/agent-envelope.mjs +296 -0
  345. package/src/tui/engine/agent-job-feed.mjs +133 -0
  346. package/src/tui/engine/boot-profile.mjs +21 -0
  347. package/src/tui/engine/labels.mjs +67 -0
  348. package/src/tui/engine/notice-text.mjs +112 -0
  349. package/src/tui/engine/notification-plan.mjs +76 -0
  350. package/src/tui/engine/queue-helpers.mjs +161 -0
  351. package/src/tui/engine/render-timing.mjs +17 -0
  352. package/src/tui/engine/session-stats.mjs +46 -0
  353. package/src/tui/engine/tool-approval.mjs +94 -0
  354. package/src/tui/engine/tool-call-fields.mjs +23 -0
  355. package/src/tui/engine/tool-card-results.mjs +234 -0
  356. package/src/tui/engine/tool-result-status.mjs +135 -0
  357. package/src/tui/engine/tool-result-text.mjs +126 -0
  358. package/src/tui/engine.mjs +405 -1385
  359. package/src/tui/figures.mjs +5 -0
  360. package/src/tui/index.jsx +105 -0
  361. package/src/tui/input-editing.mjs +60 -10
  362. package/src/tui/keyboard-protocol.mjs +2 -2
  363. package/src/tui/lib/voice-recorder.mjs +35 -19
  364. package/src/tui/markdown/format-token.mjs +11 -9
  365. package/src/tui/paste-attachments.mjs +38 -0
  366. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  367. package/src/tui/theme.mjs +6 -0
  368. package/src/tui/themes/base.mjs +2 -2
  369. package/src/tui/themes/kanagawa.mjs +4 -4
  370. package/src/tui/themes/teal.mjs +4 -5
  371. package/src/tui/themes/utils.mjs +1 -1
  372. package/src/ui/statusline-agents.mjs +213 -0
  373. package/src/ui/statusline-format.mjs +146 -0
  374. package/src/ui/statusline-segments.mjs +148 -0
  375. package/src/ui/statusline.mjs +77 -462
  376. package/src/ui/tool-card.mjs +0 -1
  377. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  378. package/src/workflows/default/WORKFLOW.md +16 -9
  379. package/src/workflows/sequential/WORKFLOW.md +16 -11
  380. package/src/workflows/solo/WORKFLOW.md +5 -1
  381. package/vendor/ink/build/display-width.js +19 -3
  382. package/vendor/ink/build/ink.js +103 -6
  383. package/vendor/ink/build/log-update.js +17 -3
  384. package/vendor/ink/build/wrap-text.js +125 -0
  385. package/scripts/_test-folder-dialog.mjs +0 -30
  386. package/scripts/fix-brief-fn.mjs +0 -35
  387. package/scripts/fix-format-tool-surface.mjs +0 -24
  388. package/scripts/fix-tool-exec-visible.mjs +0 -42
  389. package/scripts/patch-agent-brief.mjs +0 -48
  390. package/scripts/patch-app.mjs +0 -21
  391. package/scripts/patch-app2.mjs +0 -18
  392. package/scripts/patch-dist-brief.mjs +0 -96
  393. package/scripts/patch-tool-exec.mjs +0 -70
  394. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  395. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  396. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  397. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  398. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  399. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  400. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  401. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  402. package/src/standalone/agent-task-status.test.mjs +0 -76
  403. package/src/tui/components/tool-output-format.test.mjs +0 -399
  404. package/src/tui/display-width.test.mjs +0 -35
  405. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  406. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  407. package/src/tui/markdown/format-token.test.mjs +0 -354
  408. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  409. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  410. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  411. package/src/tui/prompt-history-store.test.mjs +0 -52
  412. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  413. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  414. package/src/ui/markdown.test.mjs +0 -70
  415. package/src/ui/statusline-context-label.test.mjs +0 -15
  416. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  417. 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
+ }