mixdog 1.2.3 → 1.2.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 (465) 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/probe-provider-catalog.mjs +31 -0
  5. package/scripts/provider-pingpong-live.mjs +128 -38
  6. package/scripts/session-sweep.mjs +5 -25
  7. package/src/agents/maintainer/AGENT.md +1 -1
  8. package/src/agents/maintainer/agent.json +1 -1
  9. package/src/agents/reviewer/AGENT.md +2 -4
  10. package/src/agents/security/AGENT.md +1 -2
  11. package/src/agents/writer/AGENT.md +2 -3
  12. package/src/defaults/shipped-history.json +6 -1
  13. package/src/defaults/skills/image/SKILL.md +21 -23
  14. package/src/lib/keychain-cjs.cjs +13 -11
  15. package/src/rules/agent/AGENT.md +7 -5
  16. package/src/rules/lead/LEAD.md +7 -9
  17. package/src/rules/shared/45-destructive.md +4 -0
  18. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  19. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  20. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  21. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  22. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  23. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  24. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
  25. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
  26. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  28. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
  29. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
  30. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  31. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  32. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
  33. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
  34. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
  35. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
  36. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
  37. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
  38. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  40. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  41. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  42. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  43. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
  44. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
  45. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
  46. package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
  47. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
  48. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
  49. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
  50. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
  51. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
  52. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
  53. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  54. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  55. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
  56. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
  57. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
  58. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
  59. package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
  60. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  61. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
  62. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
  63. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  64. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
  65. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
  66. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  67. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
  68. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
  69. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
  70. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  78. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
  79. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  80. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
  81. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
  82. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
  83. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
  84. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
  86. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
  87. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
  88. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
  89. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
  90. package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
  91. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
  92. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
  93. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
  94. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
  95. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
  96. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  97. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
  98. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  99. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  100. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  101. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
  102. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  103. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
  104. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
  106. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  107. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  108. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  109. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  110. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  111. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
  112. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  113. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
  114. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  115. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
  116. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  117. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  118. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  119. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
  120. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  121. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  122. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
  123. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
  124. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
  125. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  126. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  127. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  128. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
  129. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
  130. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
  131. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  132. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
  133. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
  134. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  135. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
  136. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
  137. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
  138. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  139. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  140. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  146. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  147. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  148. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  149. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
  150. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  151. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  152. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
  153. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
  154. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
  155. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  156. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
  157. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  158. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
  159. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  160. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
  161. package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
  162. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
  163. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  164. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  165. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  167. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  169. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
  170. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  171. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  172. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  173. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
  174. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  177. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  179. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +136 -196
  180. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
  181. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  182. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  183. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
  184. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  185. package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
  186. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
  187. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
  188. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  189. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
  190. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  191. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  192. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  195. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
  196. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  198. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  199. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  200. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  201. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  202. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  203. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  205. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  206. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  207. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  208. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  209. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  210. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  211. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  212. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  213. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  214. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  215. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  216. package/src/runtime/attachments/store.d.mts +9 -0
  217. package/src/runtime/attachments/store.mjs +80 -9
  218. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  219. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  220. package/src/runtime/computer-bridge/action-schema.mjs +178 -178
  221. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  222. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  223. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  224. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  225. package/src/runtime/github/tool.mjs +118 -17
  226. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  227. package/src/runtime/media/catalog.mjs +4 -4
  228. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  229. package/src/runtime/media/defaults.mjs +37 -0
  230. package/src/runtime/media/jobs.mjs +12 -2
  231. package/src/runtime/media/lanes.mjs +12 -0
  232. package/src/runtime/media/tool-defs.mjs +15 -4
  233. package/src/runtime/media/tool.mjs +41 -12
  234. package/src/runtime/media/upstream-error.mjs +72 -6
  235. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  236. package/src/runtime/memory/lib/pg/process.mjs +5 -7
  237. package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
  238. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  239. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  240. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  241. package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
  242. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  243. package/src/runtime/office/core/office-write-ledger.mjs +1 -5
  244. package/src/runtime/office/index.mjs +2 -3
  245. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  246. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  247. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  248. package/src/runtime/shared/atomic-file.d.mts +1 -1
  249. package/src/runtime/shared/background-tasks.mjs +6 -1
  250. package/src/runtime/shared/bounded-line-diff.mjs +11 -2
  251. package/src/runtime/shared/browser-launch.mjs +15 -0
  252. package/src/runtime/shared/err-text.mjs +42 -4
  253. package/src/runtime/shared/file-lock.mjs +6 -5
  254. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  255. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  256. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  257. package/src/runtime/shared/model-route-chain.mjs +48 -0
  258. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  259. package/src/runtime/shared/pid-liveness.mjs +12 -0
  260. package/src/runtime/shared/provider-api-key.mjs +6 -0
  261. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  262. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  263. package/src/runtime/shared/quiet-progress.mjs +101 -0
  264. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  265. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  266. package/src/runtime/shared/remote-intent.mjs +2 -42
  267. package/src/runtime/shared/slow-span.mjs +8 -1
  268. package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
  269. package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
  270. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  271. package/src/runtime/shared/tool-result-summary.mjs +16 -2
  272. package/src/runtime/shared/tool-status.mjs +3 -2
  273. package/src/runtime/shared/tool-surface.mjs +2 -3
  274. package/src/runtime/shared/tool-work-units.mjs +22 -15
  275. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  276. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  277. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  278. package/src/runtime/shared/transcript-writer.mjs +14 -4
  279. package/src/runtime/shared/turn-changes.mjs +2 -1
  280. package/src/runtime/shared/turn-snapshot.mjs +11 -3
  281. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  282. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  283. package/src/runtime/shared/worktrees/carry.mjs +6 -4
  284. package/src/runtime/shared/worktrees/contract.mjs +27 -1
  285. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  286. package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
  287. package/src/runtime/shared/worktrees/git-head.mjs +22 -13
  288. package/src/runtime/shared/worktrees/include.mjs +125 -7
  289. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  290. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  291. package/src/runtime/shared/worktrees/manager.mjs +378 -32
  292. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  293. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  294. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  295. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  296. package/src/runtime/terminal-bridge/client.mjs +14 -10
  297. package/src/session-runtime/boot/apis.mjs +7 -1
  298. package/src/session-runtime/boot/config.mjs +2 -0
  299. package/src/session-runtime/boot/facade.mjs +3 -0
  300. package/src/session-runtime/boot/session.mjs +3 -2
  301. package/src/session-runtime/boot/tools.mjs +3 -0
  302. package/src/session-runtime/conversation-import/service.mjs +1 -1
  303. package/src/session-runtime/goal-facade-api.mjs +2 -2
  304. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
  305. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
  306. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
  307. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  308. package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
  309. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
  310. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
  311. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  312. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  313. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  314. package/src/session-runtime/lifecycle/teardown.mjs +7 -16
  315. package/src/session-runtime/media-api.mjs +8 -0
  316. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  317. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  318. package/src/session-runtime/model-route/set-route.mjs +114 -34
  319. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  320. package/src/session-runtime/model-route-api.mjs +4 -2
  321. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  322. package/src/session-runtime/native-web-search.mjs +9 -8
  323. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  324. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  325. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  326. package/src/session-runtime/provider-models.mjs +1 -0
  327. package/src/session-runtime/provider-usage.mjs +4 -0
  328. package/src/session-runtime/route-resolution.mjs +3 -1
  329. package/src/session-runtime/runtime-core.mjs +4 -0
  330. package/src/session-runtime/runtime-facade.mjs +6 -0
  331. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  332. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  333. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  334. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  335. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  336. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  337. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  338. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  339. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  340. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  341. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  342. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  343. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
  344. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  345. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  346. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  347. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  348. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  349. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  350. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  351. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  352. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  353. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
  354. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  355. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  356. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  357. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  358. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  359. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  360. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  361. package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
  362. package/src/session-runtime/services/agent-tool.mjs +4 -0
  363. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  364. package/src/session-runtime/services/provider-admin.mjs +77 -0
  365. package/src/session-runtime/session-create/session-options.mjs +7 -5
  366. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  367. package/src/session-runtime/session-transcript.mjs +4 -5
  368. package/src/session-runtime/session-turn-api.mjs +3 -9
  369. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
  370. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  371. package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
  372. package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
  373. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
  374. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  375. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  376. package/src/session-runtime/turn/side-question-ops.mjs +1 -4
  377. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
  378. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
  379. package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
  380. package/src/session-runtime/turn/turn-run.mjs +1 -36
  381. package/src/session-runtime/usage-stats-api.mjs +4 -1
  382. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  383. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  384. package/src/session-runtime/workspace/project-branches.mjs +28 -36
  385. package/src/session-runtime/workspace/transition-steps.mjs +96 -95
  386. package/src/session-runtime/workspace/transitions.mjs +248 -68
  387. package/src/standalone/channel-transport.mjs +3 -4
  388. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  389. package/src/standalone/daemon-pg-stop.mjs +1 -3
  390. package/src/standalone/daemon-session-control.mjs +88 -0
  391. package/src/standalone/daemon-stored-session-views.mjs +23 -3
  392. package/src/standalone/daemon.mjs +2 -0
  393. package/src/standalone/local-session-runtime.mjs +11 -12
  394. package/src/standalone/session-protocol.mjs +7 -0
  395. package/src/standalone/session-runtime-inline-host.mjs +2 -0
  396. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  397. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  398. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  399. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  400. package/src/standalone/session-service/agent-tree.mjs +28 -2
  401. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  402. package/src/standalone/session-service/entries.mjs +1 -0
  403. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  404. package/src/standalone/session-service/quota-resume.mjs +28 -13
  405. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  406. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  407. package/src/standalone/session-tool-output.mjs +82 -0
  408. package/src/tui/app/app-view.jsx +2 -1
  409. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  410. package/src/tui/app/provider-setup-picker.mjs +15 -3
  411. package/src/tui/app/slash-commands.mjs +6 -0
  412. package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
  413. package/src/tui/components/Spinner.jsx +4 -0
  414. package/src/tui/components/SpinnerByline.jsx +21 -2
  415. package/src/tui/components/status-line/local-line.mjs +10 -2
  416. package/src/tui/dist/index.mjs +478 -251
  417. package/src/tui/session/active-tool-summary.mjs +1 -1
  418. package/src/tui/session/context-state.mjs +0 -3
  419. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  420. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  421. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  422. package/src/tui/session/quota-resume.mjs +140 -61
  423. package/src/tui/session/session-api/commands.mjs +4 -10
  424. package/src/tui/session/session-api/controls.mjs +12 -0
  425. package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
  426. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  427. package/src/tui/session/session-api/lifecycle.mjs +13 -11
  428. package/src/tui/session/session-api/media.mjs +2 -0
  429. package/src/tui/session/session-api/routes.mjs +81 -57
  430. package/src/tui/session/session-api/settings.mjs +3 -3
  431. package/src/tui/session/session-api/worktree.mjs +3 -2
  432. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  433. package/src/tui/session/session-flow/drain.mjs +6 -4
  434. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  435. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  436. package/src/tui/session/session-flow/queue.mjs +1 -1
  437. package/src/tui/session/tool-approval.mjs +17 -8
  438. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  439. package/src/tui/session/tui-steering-persist.mjs +3 -5
  440. package/src/tui/session/turn-quiet.mjs +53 -0
  441. package/src/tui/session/turn-stream.mjs +5 -1
  442. package/src/tui/session/turn.mjs +38 -31
  443. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  444. package/src/tui/spinner-meta.mjs +10 -0
  445. package/src/tui/spinner-verbs.mjs +3 -0
  446. package/src/ui/statusline.mjs +13 -3
  447. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  448. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  449. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  450. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
  451. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  452. package/src/session-runtime/turn/share-ops.mjs +0 -77
  453. package/src/tui/session/cross-surface-share.mjs +0 -406
  454. package/src/tui/session/live-share/delta.mjs +0 -153
  455. package/src/tui/session/live-share/mirror.mjs +0 -106
  456. package/src/tui/session/live-share/owner.mjs +0 -254
  457. package/src/tui/session/live-share/retry.mjs +0 -54
  458. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  459. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  460. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  461. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  462. package/src/tui/session/live-share/viewer.mjs +0 -99
  463. package/src/tui/session/live-share/wire.mjs +0 -44
  464. package/src/tui/session/live-share.mjs +0 -154
  465. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -90,8 +90,7 @@ const _oauthRefreshes = new Map();
90
90
  // Anthropic OAuth contract for first-party OAuth clients: Claude requests
91
91
  // are gated on this exact system-prompt prefix (Haiku 5.5 included).
92
92
  const CLAUDE_CODE_SYSTEM_PREFIX = "You are Claude Code, Anthropic's official CLI for Claude.";
93
- const OAUTH_BETA_HEADERS =
94
- 'oauth-2025-04-20,interleaved-thinking-2025-05-14,context-management-2025-06-27,extended-cache-ttl-2025-04-11';
93
+ const OAUTH_BETA_HEADERS = 'oauth-2025-04-20,interleaved-thinking-2025-05-14,context-management-2025-06-27';
95
94
 
96
95
  function logQuiet(line) {
97
96
  if (!process.env.MIXDOG_QUIET_PROVIDER_LOG) process.stderr.write(`[anthropic-oauth] ${line}\n`);
@@ -676,9 +675,7 @@ export class AnthropicOAuthProvider {
676
675
  response.status === 400 &&
677
676
  opts.fast === true &&
678
677
  !opts._fastModeRetry &&
679
- fastModeDowngraded(
680
- noteFastModeCapacityError({ httpStatus: 400, message: scrubbedText }, { fast: true })
681
- )
678
+ fastModeDowngraded(noteFastModeCapacityError({ httpStatus: 400, message: scrubbedText }, { fast: true }))
682
679
  ) {
683
680
  process.stderr.write(`[anthropic-oauth] fast mode is not enabled for this account; retrying at standard speed\n`);
684
681
  return this.send(messages, useModel, tools, { ...opts, _fastModeRetry: true });
@@ -13,6 +13,7 @@ import { ANTHROPIC_MAX_MIDSTREAM_RETRIES, parseSSEStream } from './anthropic-sse
13
13
  import { buildAnthropicBetaHeaders } from './anthropic-betas.mjs';
14
14
  import { buildAnthropicApiRequest } from './anthropic-api-request.mjs';
15
15
  import { isCustomProviderName } from './custom-reasoning.mjs';
16
+ import { createAnthropicApiKeyFetch } from './anthropic-api-key-fetch.mjs';
16
17
  import { ANTHROPIC_EFFORT_LEVELS, withEffortRejectionFallback } from './effort-rejection.mjs';
17
18
  import { armFirstByteWatchdog, createAnthropicApiTransport } from './anthropic-api-transport.mjs';
18
19
  import { createAnthropicApiRecovery } from './anthropic-api-recovery.mjs';
@@ -75,6 +76,9 @@ export class AnthropicProvider {
75
76
  return new (loadAnthropic())({
76
77
  ...credentials,
77
78
  ...(this.config.baseURL ? { baseURL: this.config.baseURL } : {}),
79
+ // Gzip only toward the official origin (decided per request URL); a
80
+ // custom-* gateway keeps the SDK's plain fetch.
81
+ ...(custom ? {} : { fetch: createAnthropicApiKeyFetch() }),
78
82
  defaultHeaders: {
79
83
  ...(betaHeaders ? { 'anthropic-beta': betaHeaders } : {}),
80
84
  ...(keyless ? { 'x-api-key': null, authorization: null } : {}),
@@ -193,6 +193,18 @@ function antigravityCatalogModels() {
193
193
  return _mirror || ANTIGRAVITY_MODELS;
194
194
  }
195
195
 
196
+ /**
197
+ * The catalog `family` ('gemini-pro', 'gemini-flash', 'gpt-oss') of a picker
198
+ * id or one of its wire ids, or null when no record carries one (Claude, or
199
+ * an id the catalog does not list).
200
+ */
201
+ export function antigravityModelFamily(model, models = antigravityCatalogModels()) {
202
+ const id = String(model || '');
203
+ const wires = (entry) => (entry?.wire && typeof entry.wire === 'object' ? Object.values(entry.wire) : [entry?.wire]);
204
+ const record = models.find((entry) => entry?.id === id) || models.find((entry) => wires(entry).includes(id));
205
+ return typeof record?.family === 'string' && record.family ? record.family : null;
206
+ }
207
+
196
208
  /**
197
209
  * Turn a picker model + effort into the wire id the gateway accepts. Tiered
198
210
  * families consume the effort (the id encodes it); a bare id whose record
@@ -228,17 +240,34 @@ function quotaRow(label, bucket) {
228
240
  };
229
241
  }
230
242
 
231
- /** Shared Gemini 5H/7D rows from retrieveUserQuotaSummary. Missing fields stay omitted. */
243
+ // The gateway's bucket ids; group names are display text and may change.
244
+ const GEMINI_5H_BUCKET_ID = 'gemini-5h';
245
+ const GEMINI_WEEKLY_BUCKET_ID = 'gemini-weekly';
246
+ const ARGON_WEEKLY_BUCKET_ID = 'gemini-argon-wtu-weekly';
247
+ // The "Claude and GPT models" group (Claude Opus, Claude Sonnet, GPT-OSS) has
248
+ // its own pair of buckets, separate from the Gemini counters.
249
+ const THIRD_PARTY_5H_BUCKET_ID = '3p-5h';
250
+ const THIRD_PARTY_WEEKLY_BUCKET_ID = '3p-weekly';
251
+
252
+ /**
253
+ * Gemini 5H/7D rows from retrieveUserQuotaSummary, the separate weekly limit
254
+ * of the Gemini 4 Argon group (its own group with only a weekly bucket), and
255
+ * the Claude/GPT-OSS 5H/7D pair. Rows are selected by bucket id and window.
256
+ * Missing fields stay omitted.
257
+ */
232
258
  export function antigravityQuotaWindows(summary) {
233
- const groups = Array.isArray(summary?.groups) ? summary.groups : [];
234
- const group = groups.find((entry) => entry && typeof entry === 'object' && entry.displayName === 'Gemini Models');
235
- const buckets = Array.isArray(group?.buckets) ? group.buckets : [];
236
- let fiveHour = null;
237
- let weekly = null;
238
- for (const bucket of buckets) {
239
- if (!bucket || typeof bucket !== 'object') continue;
240
- if (!fiveHour && bucket.window === '5h') fiveHour = bucket;
241
- if (!weekly && bucket.window === 'weekly') weekly = bucket;
242
- }
243
- return [quotaRow('5H', fiveHour), quotaRow('7D', weekly)].filter(Boolean);
259
+ const groups = (Array.isArray(summary?.groups) ? summary.groups : []).filter(
260
+ (entry) => entry && typeof entry === 'object'
261
+ );
262
+ const buckets = groups.flatMap((entry) => (Array.isArray(entry.buckets) ? entry.buckets : []));
263
+ const bucket = (id, window) =>
264
+ buckets.find((entry) => entry && typeof entry === 'object' && entry.bucketId === id && entry.window === window) ??
265
+ null;
266
+ return [
267
+ quotaRow('5H', bucket(GEMINI_5H_BUCKET_ID, '5h')),
268
+ quotaRow('7D', bucket(GEMINI_WEEKLY_BUCKET_ID, 'weekly')),
269
+ quotaRow('7D Argon', bucket(ARGON_WEEKLY_BUCKET_ID, 'weekly')),
270
+ quotaRow('5H Claude/GPT', bucket(THIRD_PARTY_5H_BUCKET_ID, '5h')),
271
+ quotaRow('7D Claude/GPT', bucket(THIRD_PARTY_WEEKLY_BUCKET_ID, 'weekly')),
272
+ ].filter(Boolean);
244
273
  }
@@ -20,7 +20,11 @@ import { preconnect } from '../../../shared/llm/http-agent.mjs';
20
20
  import { createAntigravityStreamCollector } from './antigravity-stream.mjs';
21
21
  import { createAntigravityRequest } from './antigravity-transport.mjs';
22
22
  import { finalizeAntigravityTurn } from './antigravity-response.mjs';
23
- import { ANTIGRAVITY_ACCOUNT_COOLDOWN_POLICY } from './antigravity-retry-policy.mjs';
23
+ import {
24
+ ANTIGRAVITY_ACCOUNT_COOLDOWN_POLICY,
25
+ antigravityFirstBytePolicy,
26
+ antigravityFirstResponseBudget,
27
+ } from './antigravity-retry-policy.mjs';
24
28
  import {
25
29
  CONTENT_ENDPOINT,
26
30
  ANTIGRAVITY_MODELS,
@@ -97,6 +101,13 @@ export class AntigravityOAuthProvider {
97
101
  return configured || CONTENT_ENDPOINT;
98
102
  }
99
103
 
104
+ // Longest one send to `model` may wait for response headers / first output,
105
+ // the whole transport retry ladder included; the agent watchdog's
106
+ // first-response deadlines are floored above it.
107
+ firstResponseBudget(model) {
108
+ return antigravityFirstResponseBudget(antigravityFirstBytePolicy(model || DEFAULT_ANTIGRAVITY_MODEL));
109
+ }
110
+
100
111
  _buildBody(messages, model, tools, opts) {
101
112
  const body = buildAntigravityRequest(messages, model, tools, opts, this._projectId);
102
113
  dumpAntigravityRequest(body);
@@ -169,6 +180,7 @@ export class AntigravityOAuthProvider {
169
180
  signal: passthrough.signal,
170
181
  collector,
171
182
  sleepFn: this.config.sleepFn,
183
+ firstByte: antigravityFirstBytePolicy(useModel),
172
184
  });
173
185
  try {
174
186
  try {
@@ -60,9 +60,8 @@ function coalesceClaudeThoughts(parts) {
60
60
  out.push(part);
61
61
  continue;
62
62
  }
63
- open = open
64
- ? { ...open, ...part, text: `${open.text}${typeof part.text === 'string' ? part.text : ''}` }
65
- : { ...part, text: typeof part.text === 'string' ? part.text : '' };
63
+ const partText = typeof part.text === 'string' ? part.text : '';
64
+ open = open ? { ...open, ...part, text: `${open.text}${partText}` } : { ...part, text: partText };
66
65
  if (typeof part.thoughtSignature === 'string') {
67
66
  out.push(open);
68
67
  open = null;
@@ -72,6 +71,30 @@ function coalesceClaudeThoughts(parts) {
72
71
  return out;
73
72
  }
74
73
 
74
+ // The validator-bypass sentinel is a Gemini wire token: the Claude bridge
75
+ // sends a thinking block carrying it (or no signature at all) without a
76
+ // signature and Anthropic rejects the request ("thinking.signature: Field
77
+ // required"). Only a signature this route recorded is replayed to Claude;
78
+ // any other signature is removed, and a thinking block left without one (an
79
+ // interrupted run, another model's or provider's turn, legacy metadata) is
80
+ // dropped rather than turned into visible text.
81
+ const hasOwnClaudeSignature = (part) =>
82
+ typeof part.thoughtSignature === 'string' &&
83
+ part.thoughtSignature !== '' &&
84
+ part.thoughtSignature !== THOUGHT_SIGNATURE_SENTINEL;
85
+
86
+ function claudeReplayParts(parts, own) {
87
+ const signed = parts.map((part) => {
88
+ if (!part || typeof part !== 'object' || !('thoughtSignature' in part)) return part;
89
+ if (own && hasOwnClaudeSignature(part)) return part;
90
+ const { thoughtSignature: _foreign, ...unsigned } = part;
91
+ return unsigned;
92
+ });
93
+ return coalesceClaudeThoughts(signed.filter((part) => !isEmptyPlainTextPart(part))).filter(
94
+ (part) => part?.thought !== true || hasOwnClaudeSignature(part)
95
+ );
96
+ }
97
+
75
98
  function signatureSafeMessages(messages, model) {
76
99
  const claude = isAntigravityClaude(model);
77
100
  return messages.flatMap((message) => {
@@ -80,11 +103,8 @@ function signatureSafeMessages(messages, model) {
80
103
  // Repair tool signatures only after the complete history establishes
81
104
  // the active turn, not while normalizing an isolated older message.
82
105
  const sourceParts = ownParts || toGeminiContents([message], model, { repairToolSignatures: false })[0]?.parts;
83
- const parts =
84
- claude && sourceParts
85
- ? coalesceClaudeThoughts(sourceParts.filter((part) => !isEmptyPlainTextPart(part)))
86
- : sourceParts;
87
- // A turn that held only empty parts is omitted, not sent as parts:[].
106
+ const parts = claude && sourceParts ? claudeReplayParts(sourceParts, !!ownParts) : sourceParts;
107
+ // A turn that held only empty or dropped parts is omitted, not sent as parts:[].
88
108
  if (sourceParts?.length && !parts.length) return [];
89
109
  if (!parts?.length) return [message];
90
110
  for (const part of parts) {
@@ -100,6 +120,56 @@ function signatureSafeMessages(messages, model) {
100
120
  });
101
121
  }
102
122
 
123
+ const isToolResultTurn = (content) =>
124
+ content?.role === 'user' && !!content.parts?.some((part) => part?.functionResponse);
125
+ const isPromptTurn = (content) => content?.role === 'user' && !isToolResultTurn(content);
126
+ const hasSignedThinking = (content) =>
127
+ !!content?.parts?.some((part) => part?.thought === true && hasOwnClaudeSignature(part));
128
+
129
+ // With thinking on, Claude rejects a tool loop whose turn did not open with a
130
+ // signed thinking block, and a block that was dropped (unsigned, foreign or
131
+ // compacted away) cannot be restored. The outgoing request closes that loop
132
+ // instead: the closed part loses its thinking, a short model reply
133
+ // acknowledges the tool results, and a user nudge opens a fresh turn that
134
+ // Claude starts with new thinking. The closure sits after the results of the
135
+ // turn's last unthought model message, so later steps keep the signed
136
+ // thinking that the fresh turn produced. Wire-only: the caller's messages and
137
+ // recorded replays are never touched.
138
+ function closeUnthoughtToolLoop(contents) {
139
+ if (!isToolResultTurn(contents.at(-1))) return contents;
140
+ const promptIndex = contents.findLastIndex(isPromptTurn);
141
+ const modelIndexes = [];
142
+ for (let index = promptIndex + 1; index < contents.length; index += 1) {
143
+ if (contents[index]?.role === 'model') modelIndexes.push(index);
144
+ }
145
+ if (!modelIndexes.length || hasSignedThinking(contents[modelIndexes[0]])) return contents;
146
+ const unthought = modelIndexes.findLast((index) => !hasSignedThinking(contents[index]));
147
+ let cut = unthought + 1;
148
+ let results = 0;
149
+ while (isToolResultTurn(contents[cut])) {
150
+ results += contents[cut].parts.filter((part) => part?.functionResponse).length;
151
+ cut += 1;
152
+ }
153
+ if (!results) return contents;
154
+ const closed = contents.slice(0, cut).flatMap((content) => {
155
+ if (content?.role !== 'model') return [content];
156
+ const parts = content.parts.filter((part) => part?.thought !== true);
157
+ return parts.length ? [{ ...content, parts }] : [];
158
+ });
159
+ const ack = results === 1 ? '[Tool result received.]' : `[${results} tool results received.]`;
160
+ return [
161
+ ...closed,
162
+ { role: 'model', parts: [{ text: ack }] },
163
+ { role: 'user', parts: [{ text: '[Continue.]' }] },
164
+ ...contents.slice(cut),
165
+ ];
166
+ }
167
+
168
+ // The request turns Claude thinking on through an effort level or token
169
+ // budget; a `-thinking` wire id thinks without either.
170
+ const claudeThinkingEnabled = (model, thinkingConfig) =>
171
+ !!(thinkingConfig.thinkingLevel || thinkingConfig.thinkingBudget) || /-thinking$/i.test(String(model));
172
+
103
173
  function sessionId(contents) {
104
174
  const first = contents.find((content) => content?.role === 'user');
105
175
  const text = first?.parts?.map((part) => (typeof part?.text === 'string' ? part.text : '')).join('') || '';
@@ -155,10 +225,11 @@ export function buildAntigravityRequest(messages, model, tools, opts = {}, proje
155
225
  .map((message) => message.content)
156
226
  .join('\n\n');
157
227
  const chatMessages = messages.filter((message) => message.role !== 'system');
158
- const contents = toGeminiContents(signatureSafeMessages(chatMessages, model), model);
159
- if (!contents.length) throw new Error('No messages to send');
228
+ const history = toGeminiContents(signatureSafeMessages(chatMessages, model), model);
229
+ if (!history.length) throw new Error('No messages to send');
160
230
  const claude = isAntigravityClaude(model);
161
231
  const thinkingConfig = claude ? claudeThinkingConfig(opts) : antigravityGeminiThinkingConfig(model, opts);
232
+ const contents = claude && claudeThinkingEnabled(model, thinkingConfig) ? closeUnthoughtToolLoop(history) : history;
162
233
  const generationConfig = {
163
234
  ...(claude ? { maxOutputTokens: CLAUDE_MAX_OUTPUT_TOKENS } : {}),
164
235
  ...(thinkingConfig ? { thinkingConfig } : {}),
@@ -14,11 +14,28 @@
14
14
  * rotate; advice beyond 60s surfaces at once.
15
15
  * QUOTA_EXHAUSTED (and any day/plan window): never retried here.
16
16
  *
17
+ * First byte: the gateway queues or thinks server-side and sends the
18
+ * response headers together with the first chunk, so the window is chosen
19
+ * per model class from the catalog `family`: Pro-class Gemini (Pro tiers,
20
+ * Argon) waits MIXDOG_ANTIGRAVITY_FIRST_BYTE_TIMEOUT_MS (300s, clamped to
21
+ * the provider ceiling PROVIDER_MAX_BEFORE_WARN_MS, 285s by default),
22
+ * Flash-class Gemini the shared Gemini window (60s); both apply to the
23
+ * headers and again to the first chunk. A header or first-chunk timeout is
24
+ * retried at most MIXDOG_ANTIGRAVITY_FIRST_BYTE_RETRIES times (1), each
25
+ * retry doubling the window up to that ceiling; connect, 5xx and drop
26
+ * failures keep the full ladder (MIXDOG_ANTIGRAVITY_RETRY_MAX_ATTEMPTS, 4
27
+ * attempts, at MIXDOG_ANTIGRAVITY_RETRY_BACKOFF_MS 1s / 2s / 4s). Models
28
+ * without a Gemini family (Claude, GPT-OSS, unlisted ids) keep the shared
29
+ * Gemini window on that ladder.
30
+ *
17
31
  * Replay stays gated by the stream-outcome contract: an attempt that exposed
18
32
  * text or dispatched a tool is never re-issued.
19
33
  */
20
34
  import { readStreamOutcome } from './lib/stream-outcome.mjs';
21
35
  import { DETERMINISTIC_KINDS, providerErrorKind } from './provider-error-kind.mjs';
36
+ import { PROVIDER_MAX_BEFORE_WARN_MS, firstBytePolicyBudget, resolveTimeoutMs } from '../stall-policy.mjs';
37
+ import { GEMINI_FIRST_BYTE_TIMEOUT_MS } from './gemini-stream.mjs';
38
+ import { antigravityModelFamily } from './antigravity-oauth-catalog.mjs';
22
39
 
23
40
  export const ANTIGRAVITY_CAPACITY_RETRIES = 3;
24
41
  export const ANTIGRAVITY_CAPACITY_BASE_MS = 1000;
@@ -29,21 +46,103 @@ export const ANTIGRAVITY_CAPACITY_BUDGET_MS = 60_000;
29
46
  export const ANTIGRAVITY_QUICK_RETRY_MS = 1000;
30
47
  export const ANTIGRAVITY_QUICK_RETRY_MAX_ADVICE_MS = 60_000;
31
48
 
49
+ const DEFAULT_RETRY_BACKOFF_MS = Object.freeze([1000, 1000, 2000, 4000]);
50
+
51
+ function envInt(env, name, fallback, min, max) {
52
+ const raw = env?.[name];
53
+ if (raw == null || String(raw).trim() === '') return fallback;
54
+ const n = Number(raw);
55
+ if (!Number.isInteger(n)) return fallback;
56
+ return Math.min(Math.max(n, min), max);
57
+ }
58
+
59
+ function envBackoffMs(env, name) {
60
+ const raw = String(env?.[name] ?? '').trim();
61
+ if (!raw) return DEFAULT_RETRY_BACKOFF_MS;
62
+ const steps = raw.split(',').map((step) => Number(step.trim()));
63
+ if (!steps.every((step) => Number.isInteger(step) && step >= 0)) return DEFAULT_RETRY_BACKOFF_MS;
64
+ return Object.freeze(steps);
65
+ }
66
+
67
+ /**
68
+ * The same-host ladder for everything that is not a 429, read from the
69
+ * environment: attempts (1–6), the backoff list (index n is the wait before
70
+ * attempt n) and how many first-byte timeouts a thinking model may retry.
71
+ */
72
+ export function resolveAntigravityRetryConfig(env = process.env) {
73
+ return {
74
+ maxAttempts: envInt(env, 'MIXDOG_ANTIGRAVITY_RETRY_MAX_ATTEMPTS', ANTIGRAVITY_CAPACITY_RETRIES + 1, 1, 6),
75
+ backoffMs: envBackoffMs(env, 'MIXDOG_ANTIGRAVITY_RETRY_BACKOFF_MS'),
76
+ firstByteRetries: envInt(env, 'MIXDOG_ANTIGRAVITY_FIRST_BYTE_RETRIES', 1, 0, 5),
77
+ };
78
+ }
79
+
80
+ const RETRY_CONFIG = resolveAntigravityRetryConfig();
81
+
32
82
  // withRetry options for everything that is not a 429: transient transport and
33
83
  // 5xx failures use the capacity schedule (the reference has no other same-host
34
84
  // retry; the leading duplicate is the sleep-before-attempt index).
35
85
  export const ANTIGRAVITY_RETRY = Object.freeze({
36
- maxAttempts: ANTIGRAVITY_CAPACITY_RETRIES + 1,
37
- backoffMs: Object.freeze([1000, 1000, 2000, 4000]),
86
+ maxAttempts: RETRY_CONFIG.maxAttempts,
87
+ backoffMs: RETRY_CONFIG.backoffMs,
38
88
  retryJitterRatio: ANTIGRAVITY_CAPACITY_JITTER_RATIO,
39
89
  // 429s are handled by antigravity429WaitMs, not the generic loop.
40
90
  retry429: false,
41
91
  });
42
92
 
93
+ export const ANTIGRAVITY_FIRST_BYTE_RETRIES = RETRY_CONFIG.firstByteRetries;
94
+
95
+ // Pro-class window: 300s requested, clamped to the provider ceiling.
96
+ export const ANTIGRAVITY_FIRST_BYTE_TIMEOUT_MS = resolveTimeoutMs('MIXDOG_ANTIGRAVITY_FIRST_BYTE_TIMEOUT_MS', 300_000, {
97
+ minMs: 30_000,
98
+ maxMs: PROVIDER_MAX_BEFORE_WARN_MS,
99
+ });
100
+
101
+ // First-attempt window per catalog family.
102
+ const FAMILY_FIRST_BYTE_MS = Object.freeze({
103
+ 'gemini-pro': ANTIGRAVITY_FIRST_BYTE_TIMEOUT_MS,
104
+ 'gemini-flash': GEMINI_FIRST_BYTE_TIMEOUT_MS,
105
+ });
106
+
107
+ // Models without a Gemini family: the shared Gemini window on the ordinary ladder.
108
+ export const ANTIGRAVITY_UNCLASSED_FIRST_BYTE = Object.freeze({
109
+ timeoutMs: GEMINI_FIRST_BYTE_TIMEOUT_MS,
110
+ maxMs: GEMINI_FIRST_BYTE_TIMEOUT_MS,
111
+ retries: null,
112
+ });
113
+
114
+ /**
115
+ * First-byte policy (see firstByteWindowMs) for one model, picker or wire id.
116
+ * The class comes from the catalog record's `family`.
117
+ */
118
+ export function antigravityFirstBytePolicy(model, models) {
119
+ const timeoutMs = FAMILY_FIRST_BYTE_MS[antigravityModelFamily(model, models)];
120
+ if (!timeoutMs) return ANTIGRAVITY_UNCLASSED_FIRST_BYTE;
121
+ return {
122
+ timeoutMs,
123
+ maxMs: PROVIDER_MAX_BEFORE_WARN_MS,
124
+ retries: Math.min(ANTIGRAVITY_FIRST_BYTE_RETRIES, ANTIGRAVITY_RETRY.maxAttempts - 1),
125
+ };
126
+ }
127
+
128
+ /**
129
+ * Longest a send may wait before its first output across the whole transport
130
+ * ladder ({ transportMs, semanticMs }, see firstBytePolicyBudget): the agent
131
+ * watchdog must not fire inside it. Drops and 5xx share the ladder with
132
+ * first-byte timeouts, so the budget is every backoff step of the ladder plus
133
+ * the windows of the first-byte timeouts the policy permits (all attempts for
134
+ * a policy without its own retry cap).
135
+ */
136
+ export function antigravityFirstResponseBudget(policy, backoffMs = ANTIGRAVITY_RETRY.backoffMs) {
137
+ return firstBytePolicyBudget(policy, { attempts: ANTIGRAVITY_RETRY.maxAttempts, backoffMs });
138
+ }
139
+
43
140
  /** Capacity wait for retry number `retryIndex` (0-based): 1s, 2s, 4s, 8s cap, ±10%. */
44
- export function antigravityCapacityDelayMs(retryIndex) {
141
+ function antigravityCapacityDelayMs(retryIndex) {
45
142
  const base = Math.min(ANTIGRAVITY_CAPACITY_BASE_MS * 2 ** retryIndex, ANTIGRAVITY_CAPACITY_MAX_MS);
46
- return Math.round(base * (1 - ANTIGRAVITY_CAPACITY_JITTER_RATIO + Math.random() * 2 * ANTIGRAVITY_CAPACITY_JITTER_RATIO));
143
+ return Math.round(
144
+ base * (1 - ANTIGRAVITY_CAPACITY_JITTER_RATIO + Math.random() * 2 * ANTIGRAVITY_CAPACITY_JITTER_RATIO)
145
+ );
47
146
  }
48
147
 
49
148
  export function isAntigravityCapacityError(err) {
@@ -60,7 +159,12 @@ export function antigravity429WaitMs(err, state) {
60
159
  if (status !== 429 && !(capacity && (status === 503 || status === 529))) return null;
61
160
  if (readStreamOutcome(err).replaySafe !== true) return null;
62
161
  const { kind, retryAfterMs } = providerErrorKind(err);
63
- if (DETERMINISTIC_KINDS.has(kind) || err.code === 'quota_exhausted' || err.quotaScope === 'day' || err.quotaScope === 'plan') {
162
+ if (
163
+ DETERMINISTIC_KINDS.has(kind) ||
164
+ err.code === 'quota_exhausted' ||
165
+ err.quotaScope === 'day' ||
166
+ err.quotaScope === 'plan'
167
+ ) {
64
168
  return null;
65
169
  }
66
170
  // Capacity waits at least the advised RetryInfo delay (the local schedule
@@ -80,10 +80,11 @@ export function createAntigravityStreamCollector({ tools, useModel, onToolCall,
80
80
  textLeakGuard = null;
81
81
  };
82
82
 
83
- const consume = async (res, attemptSignal) => {
83
+ const consume = async (res, attemptSignal, { firstByteTimeoutMs } = {}) => {
84
84
  try {
85
85
  return await consumeGeminiRestStreamResponse(res, {
86
86
  signal: attemptSignal,
87
+ firstByteTimeoutMs,
87
88
  onStreamDelta,
88
89
  onTextDelta: relayText,
89
90
  onChunk,
@@ -6,15 +6,22 @@
6
6
  * account-verification URL Google hides in the error details), and the
7
7
  * per-attempt hand-off of the live stream to the turn collector.
8
8
  */
9
- import { emitProviderRetryStage, markProviderRecoveryExhausted, sleepWithAbort, withRetry } from './retry-classifier.mjs';
9
+ import {
10
+ emitProviderRetryStage,
11
+ markProviderRecoveryExhausted,
12
+ sleepWithAbort,
13
+ withRetry,
14
+ } from './retry-classifier.mjs';
10
15
  import {
11
16
  ANTIGRAVITY_RETRY,
17
+ ANTIGRAVITY_UNCLASSED_FIRST_BYTE,
12
18
  antigravity429WaitMs,
13
19
  isAntigravityCapacityError,
14
20
  } from './antigravity-retry-policy.mjs';
15
- import { createTimeoutSignal } from '../stall-policy.mjs';
21
+ import { createTimeoutSignal, firstByteWindowMs } from '../stall-policy.mjs';
22
+ import { MODEL_THINKING_STAGE } from '../../../shared/quiet-progress.mjs';
23
+ import { TIMEOUT_PHASE, isFirstByteTimeout } from '../../../shared/provider-timeout-phase.mjs';
16
24
  import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
17
- import { GEMINI_FIRST_BYTE_TIMEOUT_MS } from './gemini-stream.mjs';
18
25
  import { _scrubTokens } from './antigravity-oauth-tokens.mjs';
19
26
  import { applyGeminiErrorContract } from './gemini-error-contract.mjs';
20
27
  import { DETERMINISTIC_KINDS, providerErrorKind } from './provider-error-kind.mjs';
@@ -77,8 +84,10 @@ export function antigravityError(res, text, endpoint) {
77
84
  .map((link) => link?.url)
78
85
  .find((url) => typeof url === 'string' && url.length > 0);
79
86
  const metadataUrl = (key) =>
80
- detailEntries.find((entry) => entry?.reason === 'VALIDATION_REQUIRED' && typeof entry.metadata?.[key] === 'string' && entry.metadata[key])
81
- ?.metadata[key];
87
+ detailEntries.find(
88
+ (entry) =>
89
+ entry?.reason === 'VALIDATION_REQUIRED' && typeof entry.metadata?.[key] === 'string' && entry.metadata[key]
90
+ )?.metadata[key];
82
91
  const validationUrl =
83
92
  helpUrl ||
84
93
  metadataUrl('validation_url') ||
@@ -105,19 +114,53 @@ export function antigravityError(res, text, endpoint) {
105
114
  * @param {object} deps.opts send options (stage heartbeat)
106
115
  * @param {AbortSignal|null} deps.signal retry-loop signal (session pass-through)
107
116
  * @param {{ beginAttempt: Function, consume: Function }} deps.collector
117
+ * @param {{ timeoutMs: number, maxMs: number, retries: number|null }} [deps.firstByte]
118
+ * first-byte window per attempt (antigravityFirstBytePolicy)
108
119
  * @returns {() => Promise<object>} one retried request that resolves the final payload
109
120
  */
110
- export function createAntigravityRequest({ fetchFn, endpoint, headers, body, opts, signal, collector, sleepFn }) {
121
+ export function createAntigravityRequest({
122
+ fetchFn,
123
+ endpoint,
124
+ headers,
125
+ body,
126
+ opts,
127
+ signal,
128
+ collector,
129
+ sleepFn,
130
+ firstByte = ANTIGRAVITY_UNCLASSED_FIRST_BYTE,
131
+ }) {
111
132
  const log = (attempt, lastErr, delayMs) => {
133
+ // A first-byte timeout runs on its own, shorter retry budget.
134
+ const firstByteLimited = isFirstByteTimeout(lastErr) && firstByte.retries != null;
112
135
  emitProviderRetryStage(opts.onStageChange, {
113
136
  attempt: attempt + 1,
114
- maxAttempts: ANTIGRAVITY_RETRY.maxAttempts,
137
+ maxAttempts: firstByteLimited
138
+ ? Math.min(ANTIGRAVITY_RETRY.maxAttempts, firstByte.retries + 1)
139
+ : ANTIGRAVITY_RETRY.maxAttempts,
115
140
  lastErr,
116
141
  delayMs,
117
142
  });
118
143
  process.stderr.write(`[antigravity] retry ${attempt + 1} after ${lastErr?.message || 'transient error'}\n`);
119
144
  };
120
- const attemptOnce = () =>
145
+ // Stamps what the attempt tells the user: how many attempts ran and, for a
146
+ // first-byte timeout, how long the model was given in total. A timeout past
147
+ // the first-byte retry budget ends the ladder here. A caller's cancellation
148
+ // reason may be shared by other requests and is never stamped.
149
+ const noteFailure = (err, { attemptSignal, windowMs, send }) => {
150
+ if (!err || typeof err !== 'object' || attemptSignal?.aborted) return err;
151
+ send.attempts += 1;
152
+ err.attempts = send.attempts;
153
+ if (!isFirstByteTimeout(err)) return err;
154
+ send.firstByteTimeouts += 1;
155
+ send.firstByteWaitedMs += windowMs;
156
+ err.waitedMs = send.firstByteWaitedMs;
157
+ err.providerLabel = 'Antigravity';
158
+ if (firstByte.retries != null && send.firstByteTimeouts > firstByte.retries) {
159
+ markProviderRecoveryExhausted(err, { owner: 'antigravity-first-byte', attempts: send.attempts, terminal: true });
160
+ }
161
+ return err;
162
+ };
163
+ const attemptOnce = (send) =>
121
164
  withRetry(
122
165
  async ({ signal: attemptSignal }) => {
123
166
  try {
@@ -125,37 +168,63 @@ export function createAntigravityRequest({ fetchFn, endpoint, headers, body, opt
125
168
  } catch {
126
169
  /* heartbeat */
127
170
  }
128
- const firstByte = createTimeoutSignal(attemptSignal, GEMINI_FIRST_BYTE_TIMEOUT_MS, 'Antigravity first byte');
129
- let res;
171
+ const windowMs = firstByteWindowMs(firstByte, send.firstByteTimeouts);
130
172
  try {
131
- res = await fetchFn(`${endpoint}/v1internal:streamGenerateContent?alt=sse`, {
132
- method: 'POST',
133
- headers,
134
- body,
135
- signal: firstByte.signal,
136
- dispatcher: getLlmDispatcher(),
137
- });
138
- } catch (err) {
139
- // Fetch surfaces AbortError; rethrow the timer/parent
140
- // reason so same-host retry sees EPROVIDERTIMEOUT and
141
- // a caller cancel stays a cancel.
142
- if (firstByte.signal.aborted && firstByte.signal.reason instanceof Error) {
143
- throw firstByte.signal.reason;
173
+ const firstByteTimer = createTimeoutSignal(attemptSignal, windowMs, 'Antigravity first byte');
174
+ let res;
175
+ try {
176
+ const response = fetchFn(`${endpoint}/v1internal:streamGenerateContent?alt=sse`, {
177
+ method: 'POST',
178
+ headers,
179
+ body,
180
+ signal: firstByteTimer.signal,
181
+ dispatcher: getLlmDispatcher(),
182
+ });
183
+ // The request is on the wire and its headers are pending: the
184
+ // gateway sends them only with the first chunk, so this wait is
185
+ // the model's queueing and thinking time.
186
+ try {
187
+ opts.onStageChange?.(MODEL_THINKING_STAGE);
188
+ } catch {
189
+ /* heartbeat */
190
+ }
191
+ res = await response;
192
+ } catch (err) {
193
+ // Fetch surfaces AbortError; rethrow the timer/parent
194
+ // reason so same-host retry sees EPROVIDERTIMEOUT and
195
+ // a caller cancel stays a cancel.
196
+ if (firstByteTimer.signal.aborted && firstByteTimer.signal.reason instanceof Error) {
197
+ const reason = firstByteTimer.signal.reason;
198
+ if (!attemptSignal?.aborted) reason.timeoutPhase = TIMEOUT_PHASE.HEADERS;
199
+ throw reason;
200
+ }
201
+ throw err;
202
+ } finally {
203
+ firstByteTimer.cleanup();
144
204
  }
145
- throw err;
146
- } finally {
147
- firstByte.cleanup();
148
- }
149
- if (!res.ok) {
150
- const text = await res.text().catch(() => '');
151
- const failure = antigravityError(res, text, endpoint);
152
- // Capacity is paced by the local schedule below; the generic loop
153
- // would sleep whatever wait the server names.
154
- if (isCapacityFailure(failure)) markProviderRecoveryExhausted(failure, { owner: 'antigravity-capacity' });
155
- throw failure;
205
+ // Headers arrived: the connection is live even while the model
206
+ // has not produced its first chunk.
207
+ try {
208
+ opts.onStreamDelta?.('transport');
209
+ } catch {}
210
+ if (!res.ok) {
211
+ const text = await res.text().catch(() => '');
212
+ const failure = antigravityError(res, text, endpoint);
213
+ // Capacity is paced by the local schedule below; the generic loop
214
+ // would sleep whatever wait the server names.
215
+ if (isCapacityFailure(failure)) markProviderRecoveryExhausted(failure, { owner: 'antigravity-capacity' });
216
+ throw failure;
217
+ }
218
+ try {
219
+ opts.onStageChange?.('streaming');
220
+ } catch {
221
+ /* heartbeat */
222
+ }
223
+ collector.beginAttempt();
224
+ return await collector.consume(res, attemptSignal, { firstByteTimeoutMs: windowMs });
225
+ } catch (err) {
226
+ throw noteFailure(err, { attemptSignal, windowMs, send });
156
227
  }
157
- collector.beginAttempt();
158
- return collector.consume(res, attemptSignal);
159
228
  },
160
229
  {
161
230
  ...ANTIGRAVITY_RETRY,
@@ -170,9 +239,10 @@ export function createAntigravityRequest({ fetchFn, endpoint, headers, body, opt
170
239
  // gets one quick retry, a spent quota surfaces.
171
240
  return async () => {
172
241
  const state = { capacityRetries: 0, quickRetried: false };
242
+ const send = { attempts: 0, firstByteTimeouts: 0, firstByteWaitedMs: 0 };
173
243
  for (let tried = 1; ; tried++) {
174
244
  try {
175
- return await attemptOnce();
245
+ return await attemptOnce(send);
176
246
  } catch (err) {
177
247
  const waitMs = antigravity429WaitMs(err, state);
178
248
  if (waitMs == null) {
@@ -79,7 +79,10 @@ export function modelEndpoints(item) {
79
79
  // The route for a model with these declared endpoints (null: undeclared, Chat).
80
80
  // `undefined`: nothing describes the model, so no wire is ruled out.
81
81
  function commandCodeRoute(model, endpoints, ctx = {}) {
82
- return resolveWireRoute(PROVIDER_ID, model, { ...ctx, endpoints: endpoints === undefined ? null : (endpoints ?? ['chat']) });
82
+ return resolveWireRoute(PROVIDER_ID, model, {
83
+ ...ctx,
84
+ endpoints: endpoints === undefined ? null : (endpoints ?? ['chat']),
85
+ });
83
86
  }
84
87
 
85
88
  /**
@@ -366,7 +366,9 @@ export async function resolveCursorOAuthAccessToken({ forceRefresh = false, fetc
366
366
  try {
367
367
  saveCredentials({ ...persisted, reauth_required: true });
368
368
  } catch (saveError) {
369
- process.stderr.write(`[cursor-oauth] dead-account mark failed: ${String(saveError?.message || saveError).slice(0, 200)}\n`);
369
+ process.stderr.write(
370
+ `[cursor-oauth] dead-account mark failed: ${String(saveError?.message || saveError).slice(0, 200)}\n`
371
+ );
370
372
  }
371
373
  }
372
374
  }