mixdog 1.2.3 → 1.2.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 (469) hide show
  1. package/package.json +1 -1
  2. package/scripts/gate-local.mjs +6 -4
  3. package/scripts/lib/gate-scheduler.mjs +29 -11
  4. package/scripts/mobile-release.mjs +5 -4
  5. package/scripts/probe-provider-catalog.mjs +31 -0
  6. package/scripts/provider-pingpong-live.mjs +128 -38
  7. package/scripts/session-sweep.mjs +5 -25
  8. package/src/agents/maintainer/AGENT.md +1 -1
  9. package/src/agents/maintainer/agent.json +1 -1
  10. package/src/agents/reviewer/AGENT.md +2 -4
  11. package/src/agents/security/AGENT.md +1 -2
  12. package/src/agents/writer/AGENT.md +2 -3
  13. package/src/defaults/shipped-history.json +7 -1
  14. package/src/defaults/skills/image/SKILL.md +21 -23
  15. package/src/lib/keychain-cjs.cjs +13 -11
  16. package/src/output-styles/common.md +2 -1
  17. package/src/rules/agent/AGENT.md +7 -5
  18. package/src/rules/lead/LEAD.md +13 -13
  19. package/src/rules/shared/45-destructive.md +4 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  21. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  22. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  23. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  24. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  25. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  26. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
  28. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
  31. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
  32. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  33. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  34. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
  35. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
  36. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
  37. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
  38. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
  40. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  41. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  42. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  43. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  44. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  45. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
  46. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
  47. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
  48. package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
  50. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
  51. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
  52. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
  53. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
  54. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
  55. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  56. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  57. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
  59. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
  60. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
  61. package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
  62. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  63. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
  64. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
  65. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  66. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
  67. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
  68. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  69. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
  70. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  80. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
  81. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  82. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
  83. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
  86. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
  87. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
  88. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
  89. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
  90. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
  91. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
  92. package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
  93. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
  94. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
  96. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
  97. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
  98. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  99. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
  100. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  101. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  102. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  103. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  109. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  110. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  111. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  112. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  113. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
  114. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  115. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
  116. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  117. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
  118. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  119. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  120. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  121. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  123. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  124. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
  125. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
  126. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
  127. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  128. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  129. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  130. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
  131. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
  132. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
  133. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  134. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
  135. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
  136. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
  140. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  141. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
  146. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
  147. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  148. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  149. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  150. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  151. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
  155. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
  156. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
  157. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  158. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
  161. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  162. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
  163. package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
  164. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
  165. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  167. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  169. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  173. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  174. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  178. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  179. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
  180. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  181. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +160 -212
  182. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
  183. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  184. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  185. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
  186. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  187. package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
  188. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
  189. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
  190. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  191. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
  192. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  193. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  194. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  197. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  199. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  200. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  201. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  203. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  208. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  209. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  210. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  211. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  212. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  213. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  214. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  215. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  216. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  217. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  218. package/src/runtime/attachments/store.d.mts +9 -0
  219. package/src/runtime/attachments/store.mjs +80 -9
  220. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  221. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  222. package/src/runtime/computer-bridge/action-schema.mjs +178 -178
  223. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  224. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  225. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  226. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  227. package/src/runtime/github/tool.mjs +118 -17
  228. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  229. package/src/runtime/media/catalog.mjs +4 -4
  230. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  231. package/src/runtime/media/defaults.mjs +37 -0
  232. package/src/runtime/media/jobs.mjs +12 -2
  233. package/src/runtime/media/lanes.mjs +12 -0
  234. package/src/runtime/media/tool-defs.mjs +15 -4
  235. package/src/runtime/media/tool.mjs +41 -12
  236. package/src/runtime/media/upstream-error.mjs +72 -6
  237. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  238. package/src/runtime/memory/lib/pg/process.mjs +5 -7
  239. package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
  240. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  241. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  242. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  243. package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
  244. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  245. package/src/runtime/office/core/office-write-ledger.mjs +1 -5
  246. package/src/runtime/office/index.mjs +2 -3
  247. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  248. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  249. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  250. package/src/runtime/shared/atomic-file.d.mts +1 -1
  251. package/src/runtime/shared/background-tasks.mjs +6 -1
  252. package/src/runtime/shared/bounded-line-diff.mjs +11 -2
  253. package/src/runtime/shared/browser-launch.mjs +15 -0
  254. package/src/runtime/shared/err-text.mjs +42 -4
  255. package/src/runtime/shared/file-lock.mjs +6 -5
  256. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  257. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  258. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  259. package/src/runtime/shared/model-route-chain.mjs +48 -0
  260. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  261. package/src/runtime/shared/pid-liveness.mjs +12 -0
  262. package/src/runtime/shared/provider-api-key.mjs +6 -0
  263. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  264. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  265. package/src/runtime/shared/quiet-progress.mjs +101 -0
  266. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  267. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  268. package/src/runtime/shared/remote-intent.mjs +2 -42
  269. package/src/runtime/shared/slow-span.mjs +8 -1
  270. package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
  271. package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
  272. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  273. package/src/runtime/shared/tool-result-summary.mjs +16 -2
  274. package/src/runtime/shared/tool-status.mjs +3 -2
  275. package/src/runtime/shared/tool-surface.mjs +2 -3
  276. package/src/runtime/shared/tool-work-units.mjs +22 -15
  277. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  278. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  279. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  280. package/src/runtime/shared/transcript-writer.mjs +14 -4
  281. package/src/runtime/shared/turn-changes.mjs +2 -1
  282. package/src/runtime/shared/turn-snapshot.mjs +11 -3
  283. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  284. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  285. package/src/runtime/shared/worktrees/carry.mjs +6 -4
  286. package/src/runtime/shared/worktrees/contract.mjs +27 -1
  287. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  288. package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
  289. package/src/runtime/shared/worktrees/git-head.mjs +22 -13
  290. package/src/runtime/shared/worktrees/include.mjs +125 -7
  291. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  292. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  293. package/src/runtime/shared/worktrees/manager.mjs +378 -32
  294. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  295. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  296. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  297. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  298. package/src/runtime/terminal-bridge/client.mjs +14 -10
  299. package/src/session-runtime/boot/apis.mjs +7 -1
  300. package/src/session-runtime/boot/config.mjs +2 -0
  301. package/src/session-runtime/boot/facade.mjs +3 -0
  302. package/src/session-runtime/boot/session.mjs +3 -2
  303. package/src/session-runtime/boot/tools.mjs +3 -0
  304. package/src/session-runtime/conversation-import/service.mjs +1 -1
  305. package/src/session-runtime/goal-facade-api.mjs +2 -2
  306. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
  307. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
  308. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
  309. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  310. package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
  311. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
  312. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
  313. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  314. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  315. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  316. package/src/session-runtime/lifecycle/teardown.mjs +7 -16
  317. package/src/session-runtime/media-api.mjs +8 -0
  318. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  319. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  320. package/src/session-runtime/model-route/set-route.mjs +114 -34
  321. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  322. package/src/session-runtime/model-route-api.mjs +4 -2
  323. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  324. package/src/session-runtime/native-web-search.mjs +9 -8
  325. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  326. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  327. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  328. package/src/session-runtime/provider-models.mjs +1 -0
  329. package/src/session-runtime/provider-usage.mjs +4 -0
  330. package/src/session-runtime/route-resolution.mjs +3 -1
  331. package/src/session-runtime/runtime-core.mjs +4 -0
  332. package/src/session-runtime/runtime-facade.mjs +6 -0
  333. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  334. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  335. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  336. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  337. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  338. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  339. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  340. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  341. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  342. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  343. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  344. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  345. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
  346. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  347. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  348. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  349. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  350. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  351. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  352. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  353. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  354. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  355. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
  356. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  357. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  358. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  359. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  360. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  361. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  362. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  363. package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
  364. package/src/session-runtime/services/agent-tool.mjs +4 -0
  365. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  366. package/src/session-runtime/services/provider-admin.mjs +77 -0
  367. package/src/session-runtime/session-create/session-options.mjs +7 -5
  368. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  369. package/src/session-runtime/session-transcript.mjs +4 -5
  370. package/src/session-runtime/session-turn-api.mjs +3 -9
  371. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
  372. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  373. package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
  374. package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
  375. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
  376. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  377. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  378. package/src/session-runtime/turn/side-question-ops.mjs +1 -4
  379. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
  380. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
  381. package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
  382. package/src/session-runtime/turn/turn-run.mjs +1 -36
  383. package/src/session-runtime/usage-stats-api.mjs +4 -1
  384. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  385. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  386. package/src/session-runtime/workspace/project-branches.mjs +28 -36
  387. package/src/session-runtime/workspace/transition-steps.mjs +96 -95
  388. package/src/session-runtime/workspace/transitions.mjs +248 -68
  389. package/src/standalone/channel-transport.mjs +3 -4
  390. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  391. package/src/standalone/daemon-pg-stop.mjs +1 -3
  392. package/src/standalone/daemon-session-control.mjs +88 -0
  393. package/src/standalone/daemon-stored-session-views.mjs +23 -3
  394. package/src/standalone/daemon.mjs +2 -0
  395. package/src/standalone/desktop-service-registry.mjs +32 -5
  396. package/src/standalone/local-session-runtime.mjs +11 -12
  397. package/src/standalone/session-protocol.mjs +7 -0
  398. package/src/standalone/session-runtime-inline-host.mjs +2 -0
  399. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  400. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  401. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  402. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  403. package/src/standalone/session-service/agent-tree.mjs +28 -2
  404. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  405. package/src/standalone/session-service/entries.mjs +1 -0
  406. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  407. package/src/standalone/session-service/quota-resume.mjs +28 -13
  408. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  409. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  410. package/src/standalone/session-tool-output.mjs +82 -0
  411. package/src/tui/app/app-view.jsx +2 -1
  412. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  413. package/src/tui/app/provider-setup-picker.mjs +15 -3
  414. package/src/tui/app/slash-commands.mjs +6 -0
  415. package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
  416. package/src/tui/components/Spinner.jsx +4 -0
  417. package/src/tui/components/SpinnerByline.jsx +21 -2
  418. package/src/tui/components/status-line/local-line.mjs +10 -2
  419. package/src/tui/dist/index.mjs +529 -270
  420. package/src/tui/session/active-tool-summary.mjs +1 -1
  421. package/src/tui/session/context-state.mjs +0 -3
  422. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  423. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  424. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  425. package/src/tui/session/quota-resume.mjs +140 -61
  426. package/src/tui/session/session-api/commands.mjs +4 -10
  427. package/src/tui/session/session-api/controls.mjs +12 -0
  428. package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
  429. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  430. package/src/tui/session/session-api/lifecycle.mjs +13 -11
  431. package/src/tui/session/session-api/media.mjs +2 -0
  432. package/src/tui/session/session-api/routes.mjs +81 -57
  433. package/src/tui/session/session-api/settings.mjs +3 -3
  434. package/src/tui/session/session-api/worktree.mjs +3 -2
  435. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  436. package/src/tui/session/session-flow/drain.mjs +6 -4
  437. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  438. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  439. package/src/tui/session/session-flow/queue.mjs +1 -1
  440. package/src/tui/session/tool-approval.mjs +17 -8
  441. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  442. package/src/tui/session/tui-steering-persist.mjs +3 -5
  443. package/src/tui/session/turn-quiet.mjs +53 -0
  444. package/src/tui/session/turn-stream.mjs +5 -1
  445. package/src/tui/session/turn.mjs +38 -31
  446. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  447. package/src/tui/spinner-meta.mjs +10 -0
  448. package/src/tui/spinner-verbs.mjs +3 -0
  449. package/src/ui/statusline.mjs +13 -3
  450. package/src/ui/streaming-markdown-heal.mjs +70 -18
  451. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  452. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  453. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  454. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
  455. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  456. package/src/session-runtime/turn/share-ops.mjs +0 -77
  457. package/src/tui/session/cross-surface-share.mjs +0 -406
  458. package/src/tui/session/live-share/delta.mjs +0 -153
  459. package/src/tui/session/live-share/mirror.mjs +0 -106
  460. package/src/tui/session/live-share/owner.mjs +0 -254
  461. package/src/tui/session/live-share/retry.mjs +0 -54
  462. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  463. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  464. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  465. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  466. package/src/tui/session/live-share/viewer.mjs +0 -99
  467. package/src/tui/session/live-share/wire.mjs +0 -44
  468. package/src/tui/session/live-share.mjs +0 -154
  469. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -61,7 +61,13 @@ function toolResultEntry(message, text, toolNames) {
61
61
  const isError = message.mixdog_tool_error === true;
62
62
  const toolName = toolNames.get(toolCallId) || '';
63
63
  return {
64
- toolResult: { toolCallId, content: text, media, isError },
64
+ toolResult: {
65
+ toolCallId,
66
+ content: text,
67
+ media,
68
+ isError,
69
+ ...(message.mixdog_read_window?.lineClipped === true ? { readWindow: { lineClipped: true } } : {}),
70
+ },
65
71
  entry: {
66
72
  role: 'tool',
67
73
  id: toolCallId,
@@ -170,9 +176,7 @@ export function buildRequestContext(tools, cloudRule) {
170
176
  {
171
177
  serverName: 'mixdog',
172
178
  instructions:
173
- 'Use the tools provided by the mixdog MCP server for this task. ' +
174
- 'Follow their descriptions and input schemas. Prefer them over Cursor native tools; ' +
175
- 'native tools do not directly access the Mixdog environment. ' +
179
+ 'Do not use Cursor native tools; use only the tools provided by the mixdog MCP server, following their descriptions and declared input schemas. ' +
176
180
  'If a needed tool is not available, use the provided tool discovery mechanism rather than inventing a tool.',
177
181
  },
178
182
  ]
@@ -4,6 +4,7 @@
4
4
  * close verdict and the bounded in-place restart.
5
5
  */
6
6
  import {
7
+ MAX_CONNECT_FRAME_BYTES,
7
8
  isCursorAuthError,
8
9
  isCursorThrottleError,
9
10
  isRetryableCursorStreamError,
@@ -13,6 +14,10 @@ import { emitProviderRetryStage, markProviderRecoveryExhausted, retryAfterMsFrom
13
14
  import { createFrameParser, cursorError, parseEndStream } from './cursor-wire-transport.mjs';
14
15
  import { processServerMessage } from './cursor-wire-stream-messages.mjs';
15
16
 
17
+ // A parked HTTP/2 run can still receive parallel execs. Keep their raw chunks
18
+ // with the transport until the next SSE consumer attaches.
19
+ const parkedInputs = new WeakMap();
20
+
16
21
  // Resolves after `ms`, or early when the stream is cancelled.
17
22
  function abortableSleep(ms, signal) {
18
23
  return new Promise((resolve) => {
@@ -51,7 +56,9 @@ export function createBridgeController(ctx) {
51
56
  modelParameters: run.modelParameters,
52
57
  maxMode: run.maxMode,
53
58
  sessionId: run.sessionId,
59
+ ownerSessionId: run.ownerSessionId,
54
60
  pending: state.pending,
61
+ executions: state.executions,
55
62
  sawTurnEnded: state.sawTurnEnded,
56
63
  });
57
64
  sink.finish('tool_calls');
@@ -80,13 +87,11 @@ export function createBridgeController(ctx) {
80
87
  const serverDelay = retryAfterMsFromError(error);
81
88
  // Server advice is honored in full for every retryable kind; local
82
89
  // backoff applies only when the server gave none.
83
- const delayMs = Number.isFinite(serverDelay)
84
- ? serverDelay
85
- : backoffMs(throttled ? throttleCount + 1 : retryCount + 1);
90
+ const backoffAttempt = (throttled ? throttleCount : retryCount) + 1;
91
+ const delayMs = Number.isFinite(serverDelay) ? serverDelay : backoffMs(backoffAttempt);
86
92
  const throttleOk = throttled && throttleCount < tuning.maxThrottleRetries;
87
93
  const authOk = authFailure && authCount < tuning.maxAuthRetries;
88
- const canRetry =
89
- retryCount < tuning.maxRetries && recoveryEligible && (retryable || throttleOk || authOk);
94
+ const canRetry = retryCount < tuning.maxRetries && recoveryEligible && (retryable || throttleOk || authOk);
90
95
  if (!canRetry) {
91
96
  // A fresh Cursor run owns its bounded in-place retries. Mark
92
97
  // exhaustion so the outer loop does not multiply that budget.
@@ -96,8 +101,7 @@ export function createBridgeController(ctx) {
96
101
  // A throttle that spent its bounded retries is final for the turn too.
97
102
  if (
98
103
  recoveryEligible &&
99
- ((retryable && retryCount >= tuning.maxRetries) ||
100
- (throttled && throttleCount >= tuning.maxThrottleRetries))
104
+ ((retryable && retryCount >= tuning.maxRetries) || (throttled && throttleCount >= tuning.maxThrottleRetries))
101
105
  ) {
102
106
  markProviderRecoveryExhausted(error, { owner: 'cursor-wire', attempts: retryCount + 1 });
103
107
  }
@@ -118,6 +122,9 @@ export function createBridgeController(ctx) {
118
122
  lastErr: error,
119
123
  delayMs,
120
124
  });
125
+ let restartReason = 'transient';
126
+ if (throttled) restartReason = 'throttle';
127
+ else if (authFailure) restartReason = 'auth';
121
128
  void sleep(delayMs, cancelSignal).then(async () => {
122
129
  if (isCancelled() || state.closed) return;
123
130
  try {
@@ -126,7 +133,7 @@ export function createBridgeController(ctx) {
126
133
  attempt: retryCount,
127
134
  fromCheckpoint: !throttled && Boolean(run.conversation.checkpoint),
128
135
  visibleOutput: state.visibleOutput,
129
- reason: throttled ? 'throttle' : authFailure ? 'auth' : 'transient',
136
+ reason: restartReason,
130
137
  error,
131
138
  });
132
139
  if (isCancelled() || state.closed) {
@@ -200,6 +207,11 @@ export function createBridgeController(ctx) {
200
207
  const attach = (ownedBridge, nextHeartbeat) => {
201
208
  live.bridge = ownedBridge;
202
209
  live.heartbeat = nextHeartbeat;
210
+ let inbox = parkedInputs.get(ownedBridge);
211
+ if (!inbox) {
212
+ inbox = { chunks: [], bytes: 0 };
213
+ parkedInputs.set(ownedBridge, inbox);
214
+ }
203
215
  const messageCtx = {
204
216
  state,
205
217
  filter,
@@ -208,14 +220,26 @@ export function createBridgeController(ctx) {
208
220
  tools: run.tools,
209
221
  cloudRule: run.cloudRule,
210
222
  sessionId: run.sessionId,
223
+ ownerSessionId: run.ownerSessionId,
211
224
  };
212
225
  const frameParser = createFrameParser(
213
226
  // Server requests answer on whichever bridge is live when they arrive.
214
227
  (bytes) => watchdog.progress(processServerMessage(bytes, { ...messageCtx, bridge: live.bridge })),
215
228
  (bytes) => onEndStream(ownedBridge, bytes)
216
229
  );
217
- ownedBridge.onData((chunk) => {
218
- if (live.bridge !== ownedBridge || state.closed) return;
230
+ const receive = (chunk) => {
231
+ if (live.bridge !== ownedBridge || isCancelled()) return;
232
+ if (state.closed) {
233
+ if (inbox.bytes + chunk.byteLength > MAX_CONNECT_FRAME_BYTES) {
234
+ ownedBridge.close(
235
+ cursorError('Cursor parked input exceeds the buffer limit', { code: 'stream_buffer_limit' })
236
+ );
237
+ return;
238
+ }
239
+ inbox.chunks.push(chunk);
240
+ inbox.bytes += chunk.byteLength;
241
+ return;
242
+ }
219
243
  state.chunkSeq += 1;
220
244
  try {
221
245
  frameParser(chunk);
@@ -227,9 +251,15 @@ export function createBridgeController(ctx) {
227
251
  } catch (error) {
228
252
  ownedBridge.close(error);
229
253
  }
230
- });
254
+ };
255
+ ownedBridge.onData(receive);
231
256
  ownedBridge.onClose((error) => onBridgeClose(ownedBridge, nextHeartbeat, frameParser, error));
232
257
  watchdog.start();
258
+ while (!state.closed && !isCancelled() && inbox.chunks.length) {
259
+ const chunk = inbox.chunks.shift();
260
+ inbox.bytes -= chunk.byteLength;
261
+ receive(chunk);
262
+ }
233
263
  };
234
264
 
235
265
  return { attach };
@@ -3,12 +3,14 @@
3
3
  * to the shared stream state and relayed to the SSE sink. Returns the
4
4
  * message's forward-progress kind for the watchdog.
5
5
  */
6
+ import { randomUUID } from 'node:crypto';
7
+ import { registerCursorNativeCall } from './cursor-native-context.mjs';
6
8
  import { appendAgentTrace } from '../agent-trace.mjs';
7
9
  import { decodeMessage } from './cursor-wire-protobuf.mjs';
8
10
  import { MAX_CHECKPOINT_BYTES, cursorInteractionProgress } from './cursor-wire-guards.mjs';
9
11
  import { buildCursorInteractionResponse } from './cursor-wire-interactions.mjs';
10
12
  import { cursorError } from './cursor-wire-transport.mjs';
11
- import { handleExecMessage, handleKvMessage, sendClientMessage } from './cursor-wire-exec.mjs';
13
+ import { handleExecMessage, handleKvMessage, sendClientMessage, sendToolResult } from './cursor-wire-exec.mjs';
12
14
 
13
15
  // Unknown fields seen on every live frame: AgentServerMessage field 8 (timing
14
16
  // doubles) and InteractionUpdate field 25 (epoch-ms timestamp). Never traced.
@@ -43,6 +45,31 @@ function traceUnknownFields(trace, sessionId, scope, unknown, noise) {
43
45
  }
44
46
  }
45
47
 
48
+ // Parent edit outcomes are diagnostics, not executable calls or read results.
49
+ function traceNativeEditFailure(trace, sessionId, update) {
50
+ const completed = update.toolCallCompleted;
51
+ const result = completed?.toolCall?.editToolCall?.result;
52
+ if (!result) return;
53
+ const outcome = ['fileNotFound', 'readPermissionDenied', 'writePermissionDenied', 'rejected', 'error'].find(
54
+ (key) => result[key] !== undefined
55
+ );
56
+ if (!outcome) return;
57
+ try {
58
+ trace({
59
+ sessionId,
60
+ kind: 'cursor_native_edit_failure',
61
+ provider: 'cursor',
62
+ payload: {
63
+ callId: (completed.callId || '').slice(0, 256),
64
+ modelCallId: (completed.modelCallId || '').slice(0, 256),
65
+ outcome,
66
+ },
67
+ });
68
+ } catch {
69
+ /* best-effort */
70
+ }
71
+ }
72
+
46
73
  // Relays one interaction update to the SSE stream and returns its progress.
47
74
  function applyInteractionUpdate(update, state, filter, emit) {
48
75
  if (update.textDelta?.text) {
@@ -79,9 +106,32 @@ function applyCheckpointUpdate(update, conversation, state) {
79
106
  }
80
107
 
81
108
  // Announces a newly pending native/MCP tool call as a completion chunk once.
82
- function announcePendingToolCall(state, pending, emit) {
83
- if (state.pending.some((entry) => entry.toolCallId === pending.toolCallId)) return;
109
+ function announcePendingToolCall(state, pending, emit, bridge, ownerSessionId) {
110
+ state.executions ??= new Map();
111
+ const executions = state.executions;
112
+ const execId = pending.exec.execId ?? pending.exec.id;
113
+ const previous = execId !== undefined ? executions.get(execId) : undefined;
114
+ if (previous) {
115
+ if (previous.completedResult) {
116
+ sendToolResult(
117
+ bridge,
118
+ { ...previous, exec: pending.exec },
119
+ previous.completedResult.result,
120
+ previous.completedResult.ok
121
+ );
122
+ }
123
+ return;
124
+ }
125
+ // A parent call can issue distinct executions; each needs its own local result.
126
+ if ([...executions.values(), ...state.pending].some((entry) => entry.toolCallId === pending.toolCallId)) {
127
+ pending.toolCallId = randomUUID();
128
+ }
129
+ if (execId !== undefined) executions.set(execId, pending);
130
+ registerCursorNativeCall(ownerSessionId, pending, executions);
84
131
  state.pending.push(pending);
132
+ // Native execs may await their result before the server completes a step.
133
+ // The bridge hands off only after all currently received frames are whole.
134
+ if (pending.native) state.batchBoundaryReady = true;
85
135
  emit({
86
136
  tool_calls: [
87
137
  {
@@ -101,12 +151,24 @@ function announcePendingToolCall(state, pending, emit) {
101
151
  */
102
152
  export function processServerMessage(
103
153
  bytes,
104
- { state, filter, emit, conversation, tools, cloudRule, bridge, sessionId = '', trace = appendAgentTrace }
154
+ {
155
+ state,
156
+ filter,
157
+ emit,
158
+ conversation,
159
+ tools,
160
+ cloudRule,
161
+ bridge,
162
+ sessionId = '',
163
+ ownerSessionId = '',
164
+ trace = appendAgentTrace,
165
+ }
105
166
  ) {
106
167
  const message = decodeMessage('AgentServerMessage', bytes);
107
168
  traceUnknownFields(trace, sessionId, 'agent_server_message', message.$unknown, NOISE_SERVER_FIELDS);
108
169
  if (message.interactionUpdate) {
109
170
  traceUnknownFields(trace, sessionId, 'interaction_update', message.interactionUpdate.$unknown, NOISE_UPDATE_FIELDS);
171
+ traceNativeEditFailure(trace, sessionId, message.interactionUpdate);
110
172
  }
111
173
  if (message.interactionUpdate) return applyInteractionUpdate(message.interactionUpdate, state, filter, emit);
112
174
  if (message.kvServerMessage) {
@@ -119,7 +181,7 @@ export function processServerMessage(
119
181
  }
120
182
  if (message.execServerMessage) {
121
183
  const handled = handleExecMessage(bridge, message.execServerMessage, tools, cloudRule, (pending) =>
122
- announcePendingToolCall(state, pending, emit)
184
+ announcePendingToolCall(state, pending, emit, bridge, ownerSessionId)
123
185
  );
124
186
  return handled === false ? 'park' : 'work';
125
187
  }
@@ -328,11 +328,12 @@ function createPendingToolBatchResponse(active, model, key) {
328
328
  }
329
329
 
330
330
  // Stream state shared by the sink, the message router and the bridge controller.
331
- function freshStreamState(sawTurnEnded) {
331
+ function freshStreamState(sawTurnEnded, executions) {
332
332
  return {
333
333
  outputTokens: 0,
334
334
  contextTokens: null,
335
335
  pending: [],
336
+ executions,
336
337
  closed: false,
337
338
  sawEnd: false,
338
339
  sawTurnEnded: sawTurnEnded === true,
@@ -360,7 +361,9 @@ function createStreamResponse({
360
361
  // Owning session, carried into the stored run so a session close can find
361
362
  // and tear down the pending batch's bridge/heartbeat.
362
363
  sessionId = '',
364
+ ownerSessionId = sessionId,
363
365
  sawTurnEnded = false,
366
+ executions = new Map(),
364
367
  restart = null,
365
368
  sleep = undefined,
366
369
  onStageChange = null,
@@ -376,7 +379,7 @@ function createStreamResponse({
376
379
  const stream = new ReadableStream({
377
380
  start(controller) {
378
381
  const filter = thinkingFilter();
379
- const state = freshStreamState(sawTurnEnded);
382
+ const state = freshStreamState(sawTurnEnded, executions);
380
383
  const tuning = resolveCursorStreamTuning();
381
384
  watchdog = createCursorStreamWatchdog({
382
385
  idleTimeoutMs: tuning.idleTimeoutMs,
@@ -400,7 +403,7 @@ function createStreamResponse({
400
403
  watchdog,
401
404
  sink,
402
405
  tuning,
403
- run: { key, conversation, tools, cloudRule, modelParameters, maxMode, sessionId },
406
+ run: { key, conversation, tools, cloudRule, modelParameters, maxMode, sessionId, ownerSessionId },
404
407
  runs,
405
408
  restart,
406
409
  sleep,
@@ -449,6 +452,7 @@ function resumeRun(active, toolResults, userText, model, key) {
449
452
  }
450
453
  const payload = { ...result, content: String(result.content ?? '') };
451
454
  if (pendingUserText && pending.exec.execId === lastExecId) {
455
+ if (pending.native?.resultType === 'readResult') pending.nativeUserMessage = pendingUserText;
452
456
  payload.content += `\n\n<user_message>\n${pendingUserText}\n</user_message>`;
453
457
  userTextDelivered = true;
454
458
  }
@@ -471,7 +475,11 @@ function noUserMessageResponse() {
471
475
  });
472
476
  }
473
477
 
474
- export async function handleChatCompletion(body, accessToken, { onStageChange = null, getAccessToken = null } = {}) {
478
+ export async function handleChatCompletion(
479
+ body,
480
+ accessToken,
481
+ { onStageChange = null, getAccessToken = null, resetActiveRun = false, ownerSessionId = '' } = {}
482
+ ) {
475
483
  await warmCursorClientVersion();
476
484
  const parsed = parseMessages(body.messages);
477
485
  if (
@@ -492,6 +500,7 @@ export async function handleChatCompletion(body, accessToken, { onStageChange =
492
500
  const cloudRule = parsed.systems.join('\n\n') || undefined;
493
501
  const active = activeRuns.get(key);
494
502
  if (
503
+ !resetActiveRun &&
495
504
  active &&
496
505
  parsed.toolResults.length &&
497
506
  active.bridge.alive &&
@@ -531,6 +540,7 @@ export async function handleChatCompletion(body, accessToken, { onStageChange =
531
540
  maxMode,
532
541
  key,
533
542
  sessionId,
543
+ ownerSessionId,
534
544
  onStageChange,
535
545
  restart: async ({ fromCheckpoint, reason, error }) => {
536
546
  if (reason === 'throttle') {
@@ -49,6 +49,7 @@ function toCursorMessages(messages, providerName, { nativePdf } = {}) {
49
49
  ...toolMessage,
50
50
  mixdog_tool_error: message.toolKind === 'error' || message.isError === true,
51
51
  ...(media.length ? { mixdog_tool_media: media } : {}),
52
+ ...(message.readWindow?.lineClipped === true ? { mixdog_read_window: { lineClipped: true } } : {}),
52
53
  });
53
54
  }
54
55
  return output;
@@ -545,6 +546,9 @@ function selectCursorVariant(group, { effort = null, fast = false } = {}) {
545
546
  class CursorProviderBase {
546
547
  // Cursor's chat wire has no document block: PDFs lower to text.
547
548
  nativePdf = false;
549
+ // Native read results are judged as exact source windows, so the tool
550
+ // finalizer reports their clipped lines next to the text.
551
+ consumesReadWindows = true;
548
552
 
549
553
  static inputExcludesCache = false;
550
554
  // The in-place stream retry budget is the whole recovery: a spent budget
@@ -640,6 +644,13 @@ class CursorProviderBase {
640
644
  const response = await runtime.handleChatCompletion(body, accessToken, {
641
645
  onStageChange: sendOpts.onStageChange,
642
646
  getAccessToken: (options) => this._accessToken({ signal, ...options }),
647
+ // A deliberate history reset must reach Cursor's private parked run,
648
+ // not just the orchestrator's providerState.
649
+ resetActiveRun: Boolean(sendOpts.cacheBreakIntent),
650
+ // Native read/edit capabilities are process-local. An explicit empty
651
+ // executor (the model-proxy host: tools run in the server daemon)
652
+ // keeps every call an ordinary Mixdog tool call.
653
+ ownerSessionId: String(sendOpts.toolExecutionSessionId ?? (sendOpts.sessionId || '')),
643
654
  });
644
655
  try {
645
656
  sendOpts.onStageChange?.('streaming');
@@ -699,7 +710,9 @@ class CursorProviderBase {
699
710
  const sessionScope = String(
700
711
  sendOpts.transportScope ||
701
712
  sendOpts.sessionId ||
702
- sendOpts.providerCacheKey || sendOpts.promptCacheKey || `cursor-call:${randomUUID()}`
713
+ sendOpts.providerCacheKey ||
714
+ sendOpts.promptCacheKey ||
715
+ `cursor-call:${randomUUID()}`
703
716
  );
704
717
  const openAiTools = tools?.length
705
718
  ? toOpenAITools(acceptedWireTools(tools, 'openai', sendOpts.onToolExcluded, '[cursor] tool'))
@@ -386,6 +386,14 @@ function catalogLevels(row) {
386
386
  return levels.size ? [...levels].sort(byRank) : null;
387
387
  }
388
388
 
389
+ function reasoningLevelFields(levels) {
390
+ if (!levels) return {};
391
+ return {
392
+ reasoningOptions: levels.length ? [{ type: 'effort', values: [...levels] }] : [],
393
+ reasoningLevels: [...levels],
394
+ };
395
+ }
396
+
389
397
  function effectiveRow(base, override, { providerId, discovered, newModelsHidden }) {
390
398
  const ov = override || {};
391
399
  const reasoning = ov.reasoning || {};
@@ -413,12 +421,7 @@ function effectiveRow(base, override, { providerId, discovered, newModelsHidden
413
421
  hidden,
414
422
  manual: ov.manual === true,
415
423
  supportsReasoning: levels ? levels.some((level) => level !== 'none') : base.supportsReasoning === true,
416
- ...(levels
417
- ? {
418
- reasoningOptions: levels.length ? [{ type: 'effort', values: [...levels] }] : [],
419
- reasoningLevels: [...levels],
420
- }
421
- : {}),
424
+ ...reasoningLevelFields(levels),
422
425
  customReasoning: { wireFormat: reasoning.wireFormat ?? 'standard', wireValues, replay },
423
426
  ...(replay ? { reasoningContentField: 'reasoning_content' } : {}),
424
427
  };
@@ -173,7 +173,11 @@ export async function createCustomProvider(id, config) {
173
173
  if (providerOffersWire(providerId, 'messages')) {
174
174
  const { AnthropicProvider } = await import('./anthropic.mjs');
175
175
  // The Anthropic SDK appends /v1/messages itself; the endpoint's /v1 base maps to it.
176
- messagesEngine = new AnthropicProvider({ ...engine, name: providerId, baseURL: cfg.baseURL.replace(/\/v1$/i, '') });
176
+ messagesEngine = new AnthropicProvider({
177
+ ...engine,
178
+ name: providerId,
179
+ baseURL: cfg.baseURL.replace(/\/v1$/i, ''),
180
+ });
177
181
  messagesEngine.nativePdf = false;
178
182
  }
179
183
  class CompatBase extends OpenAICompatProvider {
@@ -207,7 +211,8 @@ export async function createCustomProvider(id, config) {
207
211
  // The bound Messages engine reads the parent's model rows, so a routed
208
212
  // Messages request carries the same row-driven thinking/effort as the
209
213
  // Anthropic protocol.
210
- if (provider.messagesEngine) provider.messagesEngine.getCachedModelInfo = (model) => provider.getCachedModelInfo(model);
214
+ if (provider.messagesEngine)
215
+ provider.messagesEngine.getCachedModelInfo = (model) => provider.getCachedModelInfo(model);
211
216
  provider.customConfig = cfg;
212
217
  provider._customKeyless = keyless;
213
218
  provider._applyCustomRows(provider._customRows());
@@ -1,3 +1,4 @@
1
+ import { isVisibleStreamProgress } from '../../../shared/stream-progress.mjs';
1
2
  import { anthropicEffortLevelsFor, normalizeAnthropicEffortInput } from './anthropic-effort.mjs';
2
3
  import { CUSTOM_EFFORT_LEVELS, customEffortLevels, isCustomProviderName } from './custom-reasoning.mjs';
3
4
  import { codexModelSupportsEffortUpdates } from './openai-oauth-catalog.mjs';
@@ -72,19 +73,40 @@ export function isEffortConfigurationRejection(status, text) {
72
73
  /**
73
74
  * Runs `send(opts)`; when the model rejects the mid-conversation effort
74
75
  * update, switches the updates off for it and replays the request once
75
- * without them. The rejection happens before any output streams.
76
+ * without them. Never replay after output reached the caller, cancellation,
77
+ * or an explicit opt-out; a late error is not evidence of missing support.
76
78
  */
77
79
  export async function withEffortConfigurationFallback(provider, model, opts, send) {
80
+ let streamed = false;
81
+ const track =
82
+ (callback, isProgress = false) =>
83
+ (...args) => {
84
+ if (!isProgress || isVisibleStreamProgress(args[0])) streamed = true;
85
+ return callback(...args);
86
+ };
87
+ const tracked = { ...opts };
88
+ if (typeof opts?.onStreamDelta === 'function') tracked.onStreamDelta = track(opts.onStreamDelta, true);
89
+ if (typeof opts?.onTextDelta === 'function') tracked.onTextDelta = track(opts.onTextDelta);
90
+ if (typeof opts?.onToolCall === 'function') tracked.onToolCall = track(opts.onToolCall);
78
91
  try {
79
- return await send(opts);
92
+ return await send(tracked);
80
93
  } catch (error) {
81
94
  const status = error?.status ?? error?.httpStatus;
82
- if (opts?._effortConfigurationRetry || !isEffortConfigurationRejection(status, error?.message)) throw error;
95
+ const emitted =
96
+ streamed || error?.liveTextEmitted === true || error?.emittedToolCall === true || error?.unsafeToRetry === true;
97
+ if (
98
+ opts?._effortConfigurationRetry ||
99
+ opts?.effortConfigurationEnabled === false ||
100
+ opts?.signal?.aborted ||
101
+ emitted ||
102
+ !isEffortConfigurationRejection(status, error?.message)
103
+ )
104
+ throw error;
83
105
  markEffortConfigurationUnsupported(provider, model);
84
106
  process.stderr.write(
85
107
  `[${provider}] ${model} rejected the mid-conversation effort update; retrying once without it\n`
86
108
  );
87
- return send({ ...opts, effortConfigurationEnabled: false, _effortConfigurationRetry: true });
109
+ return send({ ...tracked, effortConfigurationEnabled: false, _effortConfigurationRetry: true });
88
110
  }
89
111
  }
90
112
  const OPENAI_PROVIDERS = new Set(['openai', 'openai-oauth']);
@@ -77,7 +77,9 @@ const GEMINI_CACHE_MIN_TOKENS = 4096;
77
77
  // Minimum prefix tokens for an explicit cache, or null when the docs exclude
78
78
  // the model from explicit caching.
79
79
  export function geminiExplicitCacheMinTokens(model) {
80
- const bare = String(model || '').replace(/^models\//i, '').toLowerCase();
80
+ const bare = String(model || '')
81
+ .replace(/^models\//i, '')
82
+ .toLowerCase();
81
83
  const major = /^gemini-(\d+)/.exec(bare);
82
84
  if (major && Number(major[1]) >= 4) return null;
83
85
  if (/^gemini-2\.5-(?:pro|flash)(?!-lite)(?:-|$)/.test(bare)) return 2048;
@@ -263,19 +265,23 @@ export function _resolveGeminiCacheUsage({ usageMetadata, cachedContent, provide
263
265
  // the prompt portion.
264
266
  const toolUseTokens = firstFinite(usageMetadata?.toolUsePromptTokenCount, usageMetadata?.tool_use_prompt_token_count);
265
267
  const inputTokens = hasExplicitPromptTokens ? promptTokens + toolUseTokens : Math.max(0, totalTokens - outputTokens);
266
- const reportedCachedTokens = firstFinite(
268
+ const reportedCachedCount = [
267
269
  // generateContent UsageMetadata field.
268
270
  usageMetadata?.cachedContentTokenCount,
269
271
  usageMetadata?.cached_content_token_count,
270
272
  // Newer SDK convenience alias documented for implicit cache hits.
271
273
  usageMetadata?.totalCachedTokens,
272
- usageMetadata?.total_cached_tokens
273
- );
274
+ usageMetadata?.total_cached_tokens,
275
+ ]
276
+ .map((value) => (value == null ? NaN : Number(value)))
277
+ .find((value) => Number.isFinite(value) && value >= 0);
278
+ const reportedCachedTokens = reportedCachedCount ?? 0;
274
279
  const cachedFallbackTokens = cachedContent ? Number(providerState?.gemini?.cacheTokenSize || 0) || 0 : 0;
275
- const rawCachedTokens = reportedCachedTokens > 0 ? reportedCachedTokens : cachedFallbackTokens;
280
+ // An explicit zero is a measured miss, not missing usage metadata.
281
+ const rawCachedTokens = reportedCachedCount ?? cachedFallbackTokens;
276
282
  const cachedTokens = inputTokens > 0 ? Math.min(rawCachedTokens, inputTokens) : rawCachedTokens;
277
283
  let cacheTokenSource = 'none';
278
- if (reportedCachedTokens > 0) cacheTokenSource = 'usage_metadata';
284
+ if (reportedCachedCount !== undefined) cacheTokenSource = 'usage_metadata';
279
285
  else if (cachedFallbackTokens > 0) cacheTokenSource = 'cache_create_fallback';
280
286
  return {
281
287
  inputTokens,
@@ -97,7 +97,10 @@ export function geminiErrorContract({ details, errorDetails, googleStatus, messa
97
97
  const scope = scopeOf(String(violation?.quotaId || ''));
98
98
  if (scope) scopes.add(scope);
99
99
  // A spent allowance is named by the typed violation, not by prose.
100
- if (String(violation?.quotaValue ?? '').trim() === '0' || LIMIT_ZERO_RE.test(String(violation?.description || ''))) {
100
+ if (
101
+ String(violation?.quotaValue ?? '').trim() === '0' ||
102
+ LIMIT_ZERO_RE.test(String(violation?.description || ''))
103
+ ) {
101
104
  zeroLimit = true;
102
105
  }
103
106
  }
@@ -121,7 +124,9 @@ export function geminiErrorContract({ details, errorDetails, googleStatus, messa
121
124
  CAPACITY_REASONS.has(reason) ||
122
125
  (!reason && scopes.size === 0 && retryAfterMs === undefined && CAPACITY_MESSAGE_RE.test(text));
123
126
  // A per-day violation outlasts any per-minute one reported with it.
124
- let quotaScope = scopes.has('day') ? 'day' : scopes.has('minute') ? 'minute' : undefined;
127
+ let quotaScope;
128
+ if (scopes.has('day')) quotaScope = 'day';
129
+ else if (scopes.has('minute')) quotaScope = 'minute';
125
130
  if (retryAfterMs === undefined) {
126
131
  const named = MESSAGE_DELAY_RE.exec(text);
127
132
  if (named) retryAfterMs = adviceMs(named[1]);
@@ -158,10 +163,13 @@ export function geminiInBandError(chunk, label) {
158
163
  if (!detail || (typeof detail !== 'object' && typeof detail !== 'string')) return null;
159
164
  const body = typeof detail === 'object' ? detail : { message: detail };
160
165
  const googleStatus = typeof body.status === 'string' ? body.status : '';
161
- const status = Number.isFinite(Number(body.code)) && Number(body.code) > 0
162
- ? Number(body.code)
163
- : GOOGLE_STATUS_HTTP[googleStatus.toUpperCase()];
164
- const err = new Error(`${label} in-band error${status ? ` ${status}` : ''}: ${String(body.message || googleStatus || 'unknown').slice(0, 300)}`);
166
+ const status =
167
+ Number.isFinite(Number(body.code)) && Number(body.code) > 0
168
+ ? Number(body.code)
169
+ : GOOGLE_STATUS_HTTP[googleStatus.toUpperCase()];
170
+ const err = new Error(
171
+ `${label} in-band error${status ? ` ${status}` : ''}: ${String(body.message || googleStatus || 'unknown').slice(0, 300)}`
172
+ );
165
173
  err.name = 'GeminiInBandError';
166
174
  if (status) {
167
175
  err.status = status;
@@ -44,10 +44,10 @@ export function buildGeminiRequest(messages, useModel, tools, opts) {
44
44
  // explicit opts.includeThoughts still wins.
45
45
  const thinkingConfig = geminiThinkingConfig(useModel, opts, { includeThoughts: true });
46
46
  const controls = geminiGenerationControls(opts);
47
- const generationConfig =
48
- thinkingConfig || Object.keys(controls).length
49
- ? { ...(thinkingConfig ? { thinkingConfig } : {}), ...controls }
50
- : undefined;
47
+ let generationConfig;
48
+ if (thinkingConfig || Object.keys(controls).length) {
49
+ generationConfig = { ...(thinkingConfig ? { thinkingConfig } : {}), ...controls };
50
+ }
51
51
  const systemInstruction =
52
52
  messages
53
53
  .filter((m) => m.role === 'system')
@@ -149,6 +149,7 @@ export function resolveGeminiUsage(response, opts, cachedContent, useModel) {
149
149
  }
150
150
 
151
151
  export function geminiSendResult(parsed, useModel, opts, resolvedUsage) {
152
+ if (parsed.providerReplay) parsed.providerReplay.requestContext = { model: useModel };
152
153
  return {
153
154
  content: parsed.content,
154
155
  model: useModel,
@@ -1,7 +1,11 @@
1
1
  // First-byte and idle watchdogs of one Gemini REST SSE body. Either timeout
2
2
  // cancels the reader and fails the pending read, so the caller surfaces a typed
3
- // timeout instead of waiting on a stalled socket.
4
- import { PROVIDER_SSE_IDLE_TIMEOUT_MS, PROVIDER_SSE_IDLE_WATCHDOG_ENABLED } from '../../stall-policy.mjs';
3
+ // timeout instead of waiting on a stalled socket. The idle timer re-arms only
4
+ // on decoded payloads (semantic progress), so it uses the semantic window.
5
+ // Each timeout names its phase (`timeoutPhase`): 'first-chunk' before any
6
+ // payload, 'idle' after one.
7
+ import { PROVIDER_SEMANTIC_IDLE_TIMEOUT_MS, PROVIDER_SSE_IDLE_WATCHDOG_ENABLED } from '../../stall-policy.mjs';
8
+ import { TIMEOUT_PHASE } from '../../../../shared/provider-timeout-phase.mjs';
5
9
 
6
10
  export function createRestStreamWatchdogs({ reader, label, firstByteTimeoutMs, timeoutError }) {
7
11
  let idleTimedOut = false;
@@ -19,11 +23,18 @@ export function createRestStreamWatchdogs({ reader, label, firstByteTimeoutMs, t
19
23
  pendingReject = null;
20
24
  reject(err);
21
25
  };
22
- const idleError = () => timeoutError(`${label} SSE idle`, PROVIDER_SSE_IDLE_TIMEOUT_MS);
26
+ const idleError = () =>
27
+ Object.assign(timeoutError(`${label} SSE idle`, PROVIDER_SEMANTIC_IDLE_TIMEOUT_MS), {
28
+ timeoutPhase: TIMEOUT_PHASE.IDLE,
29
+ });
23
30
 
24
31
  let firstByteTimer = setTimeout(() => {
25
32
  cancelReader('first byte timeout');
26
- failPending(timeoutError(`${label} first byte`, firstByteTimeoutMs));
33
+ failPending(
34
+ Object.assign(timeoutError(`${label} first byte`, firstByteTimeoutMs), {
35
+ timeoutPhase: TIMEOUT_PHASE.FIRST_CHUNK,
36
+ })
37
+ );
27
38
  }, firstByteTimeoutMs);
28
39
  firstByteTimer.unref?.();
29
40
  const clearFirstByte = () => {
@@ -46,7 +57,7 @@ export function createRestStreamWatchdogs({ reader, label, firstByteTimeoutMs, t
46
57
  idleTimedOut = true;
47
58
  cancelReader('SSE idle timeout');
48
59
  failPending(idleError());
49
- }, PROVIDER_SSE_IDLE_TIMEOUT_MS);
60
+ }, PROVIDER_SEMANTIC_IDLE_TIMEOUT_MS);
50
61
  idleTimer.unref?.();
51
62
  },
52
63
  // One reader.read() with its reject handle registered for the watchdogs;
@@ -148,7 +148,12 @@ export async function runGeminiStreamAttempts({ run, signal, onRetry, sleepFn, a
148
148
  } catch (err) {
149
149
  const waitMs = connected ? geminiMidstreamDelayMs(err, streamAttempt, signal) : null;
150
150
  if (waitMs == null) throw err;
151
- onRetry?.({ attempt: streamAttempt + 1, maxAttempts: GEMINI_MIDSTREAM_MAX_ATTEMPTS, lastErr: err, delayMs: waitMs });
151
+ onRetry?.({
152
+ attempt: streamAttempt + 1,
153
+ maxAttempts: GEMINI_MIDSTREAM_MAX_ATTEMPTS,
154
+ lastErr: err,
155
+ delayMs: waitMs,
156
+ });
152
157
  await sleepWithAbort(waitMs, signal, sleepFn, 'Gemini stream retry wait aborted');
153
158
  continue;
154
159
  }