mixdog 1.2.1 → 1.2.3

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 (557) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/scripts/provider-pingpong-live.mjs +509 -0
  6. package/src/agents/advisor/AGENT.md +1 -1
  7. package/src/agents/advisor/agent.json +1 -1
  8. package/src/agents/reviewer/AGENT.md +3 -3
  9. package/src/agents/reviewer/agent.json +1 -1
  10. package/src/defaults/shipped-history.json +6 -0
  11. package/src/defaults/skills/setup/SKILL.md +6 -1
  12. package/src/defaults/skills/setup/references/actions.md +44 -22
  13. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  14. package/src/headless-exec.mjs +15 -8
  15. package/src/lib/keychain-cjs.cjs +7 -4
  16. package/src/output-styles/common.md +11 -10
  17. package/src/repl/slash-commands.mjs +16 -1
  18. package/src/rules/agent/AGENT.md +5 -5
  19. package/src/rules/lead/LEAD.md +5 -5
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  22. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  23. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  24. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
  33. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  36. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  37. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  38. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  39. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  40. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  41. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  43. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  44. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  45. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
  46. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  47. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  48. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
  49. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
  50. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  51. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  54. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
  58. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  59. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  63. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  65. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  66. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
  70. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  71. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  72. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
  73. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
  74. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
  75. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  76. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
  77. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  79. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  80. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
  81. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  83. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
  84. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  85. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  86. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
  87. package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
  88. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  89. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  90. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  91. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  92. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  93. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
  94. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
  96. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
  97. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  99. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  100. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  102. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
  103. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
  105. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
  106. package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
  107. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  109. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
  110. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  113. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  114. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  115. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  116. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  117. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  118. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  119. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  120. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  121. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  122. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  123. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  124. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  125. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  126. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  127. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  128. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  129. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  138. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  140. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  141. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  142. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
  143. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
  144. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  145. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  147. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
  148. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  150. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
  151. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
  153. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
  154. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
  155. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
  156. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
  157. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  158. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  159. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  160. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
  161. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  163. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
  164. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  165. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
  166. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  167. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  168. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  169. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  170. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
  171. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
  172. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  173. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
  174. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
  175. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  176. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  177. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  178. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  179. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  180. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  181. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  182. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  183. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  184. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  185. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  186. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  187. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  188. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
  189. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  190. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  191. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  192. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
  193. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  195. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
  196. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  197. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  198. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  199. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  200. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  201. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  202. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  203. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  204. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  205. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  206. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  207. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  208. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  210. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  211. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  212. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
  213. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  214. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  215. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  216. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  217. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  218. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  219. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  220. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  221. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  222. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
  223. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  224. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  225. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  226. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  227. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  228. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  229. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  230. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  231. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  232. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  233. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  234. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  235. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  236. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  237. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  238. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  239. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  240. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
  241. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  242. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  243. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  244. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  245. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  246. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
  248. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
  249. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  250. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  251. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
  252. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  253. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  254. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  255. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  256. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
  257. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  258. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
  259. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  260. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  261. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  262. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  263. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  264. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  265. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  266. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  267. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
  268. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  269. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  270. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  271. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  272. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  273. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  274. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  275. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  276. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  277. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  278. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  279. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  280. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  281. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
  282. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
  283. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
  284. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  285. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  286. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  287. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  288. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  289. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  290. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  291. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  292. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
  293. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  294. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  295. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  296. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  297. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  298. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  299. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  300. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  301. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  302. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  303. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  304. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  305. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  306. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  307. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  308. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  309. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  310. package/src/runtime/github/tool.mjs +92 -2
  311. package/src/runtime/memory/index.mjs +1 -0
  312. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  313. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  314. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  315. package/src/runtime/memory/lib/pg/process.mjs +65 -50
  316. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  317. package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
  318. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  319. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  320. package/src/runtime/office/README.md +2 -2
  321. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  322. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  323. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  324. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  325. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  326. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  327. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  328. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  329. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  330. package/src/runtime/office/core/office-sessions.mjs +5 -0
  331. package/src/runtime/office/core/office-transactions.mjs +3 -0
  332. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  333. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  334. package/src/runtime/office/index.mjs +30 -0
  335. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  336. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  337. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  338. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  339. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  340. package/src/runtime/office/shared/values.mjs +0 -5
  341. package/src/runtime/shared/background-tasks.mjs +92 -14
  342. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  343. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  344. package/src/runtime/shared/buffered-appender.mjs +18 -0
  345. package/src/runtime/shared/config.mjs +78 -18
  346. package/src/runtime/shared/err-text.mjs +31 -0
  347. package/src/runtime/shared/error-presentation.mjs +159 -19
  348. package/src/runtime/shared/file-permissions.d.mts +6 -1
  349. package/src/runtime/shared/file-permissions.mjs +54 -6
  350. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  351. package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
  352. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  353. package/src/runtime/shared/llm/model-catalog.mjs +53 -40
  354. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  355. package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
  356. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  357. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  358. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  359. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  360. package/src/runtime/shared/loopback-listener.mjs +9 -0
  361. package/src/runtime/shared/model-display.mjs +13 -0
  362. package/src/runtime/shared/provider-api-key.mjs +2 -0
  363. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  364. package/src/runtime/shared/review-diff.mjs +52 -0
  365. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  366. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  367. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  368. package/src/runtime/shared/slow-span.mjs +114 -0
  369. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  370. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  371. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  372. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  373. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  374. package/src/runtime/shared/tool-card-model.mjs +5 -2
  375. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  376. package/src/runtime/shared/tool-primitives.mjs +13 -0
  377. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  378. package/src/runtime/shared/tool-surface.mjs +18 -3
  379. package/src/runtime/shared/tool-work-units.mjs +40 -4
  380. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  381. package/src/runtime/shared/transcript-writer.mjs +10 -2
  382. package/src/runtime/shared/turn-changes.mjs +670 -274
  383. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  384. package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
  385. package/src/runtime/shared/turn-snapshot.mjs +986 -690
  386. package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
  387. package/src/runtime/shared/user-data-guard.mjs +262 -49
  388. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  389. package/src/runtime/shared/worktrees/contract.mjs +34 -24
  390. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  391. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  392. package/src/runtime/shared/worktrees/git.mjs +8 -3
  393. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  394. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  395. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  396. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  397. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  398. package/src/runtime/terminal-bridge/client.mjs +44 -11
  399. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  400. package/src/runtime/tidy/apply.mjs +47 -2
  401. package/src/runtime/tidy/run-engines.mjs +11 -5
  402. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  403. package/src/session-runtime/boot/apis.mjs +19 -5
  404. package/src/session-runtime/boot/facade.mjs +1 -0
  405. package/src/session-runtime/boot/infrastructure.mjs +12 -1
  406. package/src/session-runtime/boot/session.mjs +0 -1
  407. package/src/session-runtime/boot/tools.mjs +4 -1
  408. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  409. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  410. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  411. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  412. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  413. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  414. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  415. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  416. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
  417. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  418. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  419. package/src/session-runtime/lifecycle/teardown.mjs +73 -8
  420. package/src/session-runtime/lifecycle-api.mjs +1 -0
  421. package/src/session-runtime/mcp-glue/connect.mjs +46 -14
  422. package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
  423. package/src/session-runtime/mcp-glue.mjs +3 -0
  424. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  425. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  426. package/src/session-runtime/model-route/set-route.mjs +85 -17
  427. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  428. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  429. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  430. package/src/session-runtime/native-web-search.mjs +10 -1
  431. package/src/session-runtime/new-session-config.mjs +4 -2
  432. package/src/session-runtime/provider-auth/login.mjs +4 -0
  433. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  434. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  435. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  436. package/src/session-runtime/resource-extension-sync.mjs +4 -0
  437. package/src/session-runtime/resource-mcp-api.mjs +98 -2
  438. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  439. package/src/session-runtime/runtime-review-api.mjs +21 -2
  440. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  441. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  442. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  443. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  444. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  445. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  446. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  447. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  448. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  449. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  450. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  451. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  452. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  453. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  454. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  455. package/src/session-runtime/services/agent-tool.mjs +3 -0
  456. package/src/session-runtime/services/channel-admin.mjs +19 -3
  457. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  458. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  459. package/src/session-runtime/services/provider-admin.mjs +81 -15
  460. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  461. package/src/session-runtime/session-turn-api.mjs +14 -5
  462. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  463. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  464. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  465. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  466. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  467. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  468. package/src/session-runtime/skills-api.mjs +3 -5
  469. package/src/session-runtime/tool-surface.mjs +5 -1
  470. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  471. package/src/session-runtime/turn/session-ops.mjs +7 -5
  472. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  473. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  474. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  475. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  476. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  477. package/src/session-runtime/turn/turn-run.mjs +25 -9
  478. package/src/session-runtime/usage-stats-api.mjs +43 -11
  479. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  480. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  481. package/src/session-runtime/workspace/transitions.mjs +190 -15
  482. package/src/standalone/daemon-agent-control.mjs +9 -1
  483. package/src/standalone/daemon-drain-policy.mjs +8 -0
  484. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  485. package/src/standalone/daemon-owner.mjs +17 -4
  486. package/src/standalone/daemon-pg-stop.mjs +51 -0
  487. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  488. package/src/standalone/daemon-stop-budget.mjs +18 -0
  489. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  490. package/src/standalone/daemon-telemetry.mjs +74 -0
  491. package/src/standalone/daemon.mjs +64 -8
  492. package/src/standalone/desktop-service-registry.mjs +5 -0
  493. package/src/standalone/local-session-runtime.mjs +70 -19
  494. package/src/standalone/session-client.mjs +42 -0
  495. package/src/standalone/session-protocol.mjs +14 -0
  496. package/src/standalone/session-proxy/projection.mjs +41 -4
  497. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  498. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  499. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  500. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  501. package/src/standalone/session-service/agent-tree.mjs +12 -0
  502. package/src/standalone/session-service/quota-resume.mjs +8 -0
  503. package/src/standalone/session-service/retention/busy.mjs +15 -1
  504. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  505. package/src/standalone/session-service-api.mjs +11 -1
  506. package/src/standalone/session-service.mjs +1 -0
  507. package/src/standalone/session-state-patch.d.mts +2 -1
  508. package/src/standalone/session-state-patch.mjs +41 -1
  509. package/src/tui/App.jsx +25 -0
  510. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  511. package/src/tui/app/app-view.jsx +1 -0
  512. package/src/tui/app/btw-controller.mjs +118 -0
  513. package/src/tui/app/create-app-pickers.mjs +6 -0
  514. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  515. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  516. package/src/tui/app/extension-pickers.mjs +2 -1
  517. package/src/tui/app/model-options.mjs +11 -16
  518. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  519. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  520. package/src/tui/app/slash-commands.mjs +20 -5
  521. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  522. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  523. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  524. package/src/tui/app/use-global-key-input.mjs +5 -12
  525. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  526. package/src/tui/components/BtwPanel.jsx +53 -0
  527. package/src/tui/components/QuestionPanel.jsx +275 -0
  528. package/src/tui/components/StatusLine.jsx +2 -0
  529. package/src/tui/components/question-panel-model.mjs +156 -0
  530. package/src/tui/components/status-line/local-line.mjs +5 -2
  531. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  532. package/src/tui/dist/index.mjs +3221 -1500
  533. package/src/tui/session/context-state.mjs +4 -2
  534. package/src/tui/session/quota-resume.mjs +46 -14
  535. package/src/tui/session/session-api/commands.mjs +43 -24
  536. package/src/tui/session/session-api/controls.mjs +2 -2
  537. package/src/tui/session/session-api/extensions.mjs +22 -0
  538. package/src/tui/session/session-api/integrations.mjs +16 -2
  539. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  540. package/src/tui/session/session-api/lifecycle.mjs +7 -2
  541. package/src/tui/session/session-api/routes.mjs +71 -7
  542. package/src/tui/session/session-api/settings.mjs +11 -14
  543. package/src/tui/session/session-api.mjs +1 -0
  544. package/src/tui/session/session-flow/drain.mjs +7 -1
  545. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  546. package/src/tui/session/tool-approval.mjs +10 -7
  547. package/src/tui/session/transcript-spill.mjs +14 -7
  548. package/src/tui/session/turn-stream.mjs +174 -31
  549. package/src/tui/session/turn.mjs +46 -16
  550. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  551. package/src/ui/statusline-agents.mjs +15 -4
  552. package/src/ui/statusline.mjs +7 -3
  553. package/src/ui/streaming-markdown-heal.mjs +34 -3
  554. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  555. package/src/workflows/default/WORKFLOW.md +3 -1
  556. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  557. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -179,6 +179,9 @@ const PROVIDER_MODULES = {
179
179
  openai: ['./openai-ws.mjs', 'OpenAIDirectProvider'],
180
180
  'mixdog-local': ['./mixdog-local.mjs', 'MixdogLocalProvider'],
181
181
  'opencode-go': ['./opencode-go.mjs', 'OpenCodeGoProvider'],
182
+ // Multi-wire preset gateways (wire-route.mjs picks the wire per model).
183
+ openrouter: ['./openrouter.mjs', 'OpenRouterProvider'],
184
+ deepseek: ['./deepseek.mjs', 'DeepSeekProvider'],
182
185
  };
183
186
 
184
187
  // User-defined providers (cfg.type === 'custom') are keyed by a generated
@@ -209,7 +212,7 @@ async function instantiateProvider(name, Ctor, cfg, proxyChannel = null) {
209
212
  return wrapProviderAdmission(createModelProxyProvider(name, cfg, proxyChannel ?? getModelProxyChannel()), name);
210
213
  }
211
214
  if (isCustomProviderConfig(name, cfg)) return wrapProviderAdmission(await Ctor(name, cfg), name);
212
- if (Object.hasOwn(OPENAI_COMPAT_PRESETS, name) && name !== 'opencode-go') {
215
+ if (Object.hasOwn(OPENAI_COMPAT_PRESETS, name) && !Object.hasOwn(PROVIDER_MODULES, name)) {
213
216
  return wrapProviderAdmission(new Ctor(name, cfg), name);
214
217
  }
215
218
  return createAccountPoolProvider(name, () => wrapProviderAdmission(new Ctor(cfg), name));
@@ -5,6 +5,7 @@ import {
5
5
  PROVIDER_RETRY_JITTER_RATIO,
6
6
  PROVIDER_RETRY_MAX_ATTEMPTS,
7
7
  } from '../stall-policy.mjs';
8
+ import { providerErrorKind } from './provider-error-kind.mjs';
8
9
 
9
10
  /** Anthropic request budget: 10 retries (11 attempts).
10
11
  * CLAUDE_CODE_MAX_RETRIES is intentionally read per request for reload/tests.
@@ -32,17 +33,23 @@ export function anthropicRequestTimeoutMs() {
32
33
  return Number.isFinite(parsed) && parsed > 0 ? parsed : 600_000;
33
34
  }
34
35
 
36
+ // Consecutive overloads after which Anthropic switches to its fallback model
37
+ // (passed to withRetry as `overloadFallbackAfter`).
35
38
  export const ANTHROPIC_MAX_CONSECUTIVE_529 = 3;
36
39
 
37
- export class AnthropicFallbackTriggeredError extends Error {
40
+ /** Thrown by withRetry when `overloadFallbackAfter` consecutive overloads hand the send to `fallbackModel`. */
41
+ export class ModelFallbackTriggeredError extends Error {
38
42
  constructor(originalModel, fallbackModel, cause) {
39
- super(`Anthropic model fallback triggered: ${originalModel} -> ${fallbackModel}`, { cause });
40
- this.name = 'AnthropicFallbackTriggeredError';
43
+ super(`Model fallback triggered: ${originalModel} -> ${fallbackModel}`, { cause });
44
+ this.name = 'ModelFallbackTriggeredError';
41
45
  this.originalModel = originalModel;
42
46
  this.fallbackModel = fallbackModel;
43
47
  }
44
48
  }
45
49
 
50
+ // Existing provider imports keep working: the same class under its old name.
51
+ export const AnthropicFallbackTriggeredError = ModelFallbackTriggeredError;
52
+
46
53
  // Default backoff schedule used by withRetry when caller does not override.
47
54
  // Mirrors anthropic-oauth's 5-attempt curve (immediate + 1s/2s/4s/8s) so the
48
55
  // total cap stays under 15s. Total upper bound = sum = 15s.
@@ -51,9 +58,36 @@ export const DEFAULT_MAX_ATTEMPTS = PROVIDER_RETRY_MAX_ATTEMPTS;
51
58
 
52
59
  const MIDSTREAM_BACKOFF_MS = [250, 1000, 2000, 4000];
53
60
 
54
- export function midstreamBackoffFor(retryNumber, schedule = MIDSTREAM_BACKOFF_MS) {
55
- const raw = schedule[Math.min(Math.max(retryNumber, 1), schedule.length) - 1];
56
- return jitterDelayMs(raw);
61
+ const ADVICE_RETRYABLE_KINDS = new Set(['overloaded', 'rate_limited', 'transient']);
62
+
63
+ /**
64
+ * The wait before a mid-stream re-issue: the server's advice (Retry-After /
65
+ * retryAfterMs) in full for a retryable kind — never capped below its value —
66
+ * else the caller's bounded backoff step. Advice never makes a terminal kind
67
+ * retryable; that is the classifier's verdict, not this wait's. The retry
68
+ * COUNT stays the caller's budget; the sleep stays the caller's abortable one.
69
+ */
70
+ export function midstreamRetryDelayMs(err, backoffMs) {
71
+ const { kind, retryAfterMs } = providerErrorKind(err);
72
+ if (retryAfterMs != null && ADVICE_RETRYABLE_KINDS.has(kind)) return Math.max(0, retryAfterMs);
73
+ return Math.max(0, Number(backoffMs) || 0);
74
+ }
75
+
76
+ /** The mid-stream wait for `retryNumber`; pass the failure as `err` so server
77
+ * advice on a retryable kind replaces the jittered step (midstreamRetryDelayMs). */
78
+ // `schedule` / `jitterRatio` default to the shared values; a provider passes
79
+ // its own (e.g. openai-retry-policy.mjs).
80
+ export function midstreamBackoffFor(
81
+ retryNumber,
82
+ schedule = MIDSTREAM_BACKOFF_MS,
83
+ err = null,
84
+ jitterRatio,
85
+ jitterMode = 'symmetric'
86
+ ) {
87
+ const steps = schedule || MIDSTREAM_BACKOFF_MS;
88
+ const raw = steps[Math.min(Math.max(retryNumber, 1), steps.length) - 1];
89
+ const step = jitterDelayMs(raw, jitterRatio ?? PROVIDER_RETRY_JITTER_RATIO, jitterMode);
90
+ return err ? midstreamRetryDelayMs(err, step) : step;
57
91
  }
58
92
 
59
93
  export function jitterDelayMs(ms, ratio = PROVIDER_RETRY_JITTER_RATIO, mode = 'symmetric') {
@@ -62,7 +96,12 @@ export function jitterDelayMs(ms, ratio = PROVIDER_RETRY_JITTER_RATIO, mode = 's
62
96
  const r = Math.min(Math.max(Number(ratio) || 0, 0), 1);
63
97
  if (!r) return Math.round(base);
64
98
  const spread = base * r;
65
- const offset = mode === 'positive' ? Math.random() * spread : (Math.random() * 2 - 1) * spread;
99
+ // 'positive': upward only; 'negative': downward only, base × (1 − r·rand);
100
+ // otherwise symmetric ±r.
101
+ let offset;
102
+ if (mode === 'positive') offset = Math.random() * spread;
103
+ else if (mode === 'negative') offset = -Math.random() * spread;
104
+ else offset = (Math.random() * 2 - 1) * spread;
66
105
  return Math.max(0, Math.round(base + offset));
67
106
  }
68
107
 
@@ -1,6 +1,31 @@
1
1
  // Structural error classification: typed status, transience, auth, context
2
2
  // overflow, retry-after and stream-close verdicts shared by every provider.
3
3
  import { readStreamOutcome } from './lib/stream-outcome.mjs';
4
+ import {
5
+ BARE_FETCH_TRANSPORT_MESSAGE_RE,
6
+ DETERMINISTIC_KINDS,
7
+ QUOTA_KINDS,
8
+ REQUEST_SIZE_PATTERNS,
9
+ TLS_RECORD_FAILURE_RE,
10
+ TOKEN_CONTEXT_OVERFLOW_PATTERNS,
11
+ TRANSIENT_SDK_NAMES,
12
+ boundedCauseChain,
13
+ isToolSurfaceExceedsContextError,
14
+ isTransientErrorCode,
15
+ providerErrorKind,
16
+ typedCodeKind,
17
+ typedErrorCode,
18
+ } from './provider-error-kind.mjs';
19
+
20
+ export {
21
+ boundedCauseChain,
22
+ errorHeaderValue,
23
+ headerValue,
24
+ isTransientErrorCode,
25
+ providerErrorKind,
26
+ retryAfterMsFromError,
27
+ typedErrorCode,
28
+ } from './provider-error-kind.mjs';
4
29
 
5
30
  // HTTP statuses considered transient — safe to retry with backoff.
6
31
  // 408 — request timeout
@@ -15,22 +40,18 @@ export const TRANSIENT_STATUSES = new Set([408, 409, 425]);
15
40
  // 400/422 — bad request (deterministic)
16
41
  const AUTH_STATUSES = new Set([401, 403]);
17
42
  const PERMANENT_STATUSES = new Set([400, 404, 405, 410, 415, 422]);
18
- // Cloudflare origin-TLS pages never clear on retry (grok-build edge_client).
43
+ // Cloudflare origin-TLS pages never clear on retry.
19
44
  export const TERMINAL_EDGE_STATUSES = new Set([525, 526]);
20
45
  const GEMINI_TRANSIENT_RPC_CODES = new Set(['UNAVAILABLE', 'DEADLINE_EXCEEDED', 'ABORTED', 'INTERNAL']);
21
46
  const PREVIOUS_RESPONSE_NOT_FOUND = 'previous_response_not_found';
22
47
  export const WEBSOCKET_CONNECTION_LIMIT = 'websocket_connection_limit_reached';
23
- const RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded';
24
- const CONTEXT_OVERFLOW_CODES = new Set(['context_length_exceeded', 'context_window_exceeded', 'request_too_large']);
25
- const TRANSIENT_SDK_NAMES = new Set([
26
- 'APIConnectionError',
27
- 'APIConnectionTimeoutError',
28
- 'ConnectTimeoutError',
29
- 'HeadersTimeoutError',
30
- 'BodyTimeoutError',
48
+ // Token-context codes only: a byte-size `request_too_large` is not cured by
49
+ // compaction (see isContextOverflowError).
50
+ const CONTEXT_OVERFLOW_CODES = new Set([
51
+ 'context_length_exceeded',
52
+ 'context_window_exceeded',
53
+ 'model_context_window_exceeded',
31
54
  ]);
32
- const ANTHROPIC_RESET_HEADER = 'anthropic-ratelimit-unified-reset';
33
- const ANTHROPIC_RESET_CAP_MS = 300_000;
34
55
 
35
56
  // Structured status fields a provider error / wire event may carry. A value is
36
57
  // accepted only when it is a real numeric HTTP status; string codes
@@ -59,8 +80,11 @@ const statusOfError = (err) => Number(err?.httpStatus || err?.status || err?.res
59
80
 
60
81
  // The verdict a typed HTTP status (or a typed stream shape) gives, in
61
82
  // precedence order; null when the status decides nothing.
62
- function classifyByStatus(err, status) {
83
+ function classifyByStatus(err, status, options = {}) {
63
84
  if (AUTH_STATUSES.has(status)) return 'auth';
85
+ // Opt-in: 499 "client closed request" from Google
86
+ // frontends is retried; others keep it a deterministic 4xx.
87
+ if (status === 499 && options.retry499 === true) return 'transient';
64
88
  // Stale previous_response_id is recoverable by dropping the chain and
65
89
  // re-issuing a full frame, which is the retryable path. A typed
66
90
  // 400 here is not a deterministic payload refusal.
@@ -90,7 +114,7 @@ function classifyByStatus(err, status) {
90
114
  * 'unknown' — neither; default to permanent in safety-critical paths,
91
115
  * or retry once in best-effort paths.
92
116
  */
93
- export function classifyError(err) {
117
+ export function classifyError(err, options = {}) {
94
118
  if (!err) return 'unknown';
95
119
  // Canonical stream-outcome contract owns replay safety: exposed
96
120
  // text/reasoning or a dispatched/ambiguous complete tool call makes
@@ -105,14 +129,34 @@ export function classifyError(err) {
105
129
  // across the bounded chain before considering stale connection causes.
106
130
  const chain = boundedCauseChain(err);
107
131
  if (chain.some(isExplicitUserAbortError)) return 'permanent';
108
- // Current typed HTTP status outranks stale stream/connection annotations.
132
+ // A typed provider code outranks the HTTP status (429+server_is_overloaded
133
+ // is an overload, 403+cyber_policy a policy refusal, 5xx+insufficient_quota
134
+ // a billing refusal).
135
+ // Typed evidence only: message wording never synthesizes a verdict here.
136
+ const { kind } = providerErrorKind(err, { text: false });
109
137
  const status = statusOfError(err);
110
- return classifyByStatus(err, status) || classifyByTransport(err, chain, status) || 'unknown';
138
+ // Opt-in: a status-only 499 "client closed request" is retried instead of
139
+ // read as a 4xx; a typed code on it decides as usual.
140
+ if (status === 499 && options.retry499 === true && kind === 'invalid_request' && !typedCodeKind(err)) {
141
+ return 'transient';
142
+ }
143
+ if (kind === 'auth' || kind === 'permission') return 'auth';
144
+ if (DETERMINISTIC_KINDS.has(kind)) return 'permanent';
145
+ // An origin-TLS edge failure is final whatever code accompanies it.
146
+ if (TERMINAL_EDGE_STATUSES.has(status)) return 'permanent';
147
+ // A deterministic wire code outranks a numeric 5xx on the same event.
148
+ if (classifyWireErrorEvent(err) === 'permanent') return 'permanent';
149
+ if (kind === 'overloaded') return 'transient';
150
+ // A typed transient kind decides whatever status accompanies it (401 +
151
+ // server_error is a server fault).
152
+ if (kind === 'transient') return 'transient';
153
+ // Current typed HTTP status outranks stale stream/connection annotations.
154
+ return classifyByStatus(err, status, options) || classifyByTransport(err, chain, status) || 'unknown';
111
155
  }
112
156
 
113
157
  // A turn that ended on a malformed or unexpected tool call produced no usable
114
- // call at all (the typed finish reason says so); the reference client re-asks
115
- // the same request, bounded, instead of failing the turn.
158
+ // call at all (the typed finish reason says so); the same request is re-asked,
159
+ // bounded, instead of failing the turn.
116
160
  const INVALID_TOOL_CALL_FINISH_REASONS = new Set(['MALFORMED_FUNCTION_CALL', 'UNEXPECTED_TOOL_CALL']);
117
161
 
118
162
  function isInvalidToolCallFinish(err) {
@@ -132,9 +176,9 @@ function classifyByTransport(err, chain, status) {
132
176
  // so without this it classified as 'unknown' and no loop-level replay was
133
177
  // ever attempted (observed live: pooled WS retired by the server between
134
178
  // turns → close 1000 before response.created → the whole turn failed).
135
- // Reference behavior retries the same disconnect (codex `CodexErr::Stream`
136
- // is_retryable, and a stream fallback/retry applies); the exposure deny above
137
- // still fails closed for anything already relayed or dispatched.
179
+ // The same disconnect is retryable (a stream fallback/retry applies); the
180
+ // exposure deny above still fails closed for anything already relayed or
181
+ // dispatched.
138
182
  if (isNonTerminalStreamClose(err)) return 'transient';
139
183
 
140
184
  // Cursor's resumed tool-result stream cannot safely reopen the same wire
@@ -172,58 +216,6 @@ function classifyByTransport(err, chain, status) {
172
216
  return classifyWireErrorEvent(err) || null;
173
217
  }
174
218
 
175
- const MAX_CAUSE_CHAIN_DEPTH = 8;
176
- // 'terminated' / 'other side closed' / 'socket hang up' are the body-read
177
- // forms of the same disconnect (undici aborts the response body when the peer
178
- // closes mid-stream and may not attach a cause).
179
- const BARE_FETCH_TRANSPORT_MESSAGE_RE =
180
- /^(?:fetch failed|failed to fetch|couldn'?t fetch\.?|load failed|network error|terminated|other side closed|socket hang up)$/i;
181
- const TRANSIENT_ERROR_CODES = new Set([
182
- 'ECONNRESET',
183
- 'ETIMEDOUT',
184
- 'ESOCKETTIMEDOUT',
185
- 'EAI_AGAIN',
186
- 'ENOTFOUND',
187
- 'EAI_NODATA',
188
- 'ECONNREFUSED',
189
- 'ENETUNREACH',
190
- 'EHOSTUNREACH',
191
- 'EPIPE',
192
- 'EPROVIDERTIMEOUT',
193
- 'EGEMINITIMEOUT',
194
- 'ESTREAMSTALL',
195
- 'EWSACQUIRETIMEOUT',
196
- 'UND_ERR_SOCKET',
197
- 'UND_ERR_CONNECT_TIMEOUT',
198
- 'UND_ERR_HEADERS_TIMEOUT',
199
- 'UND_ERR_BODY_TIMEOUT',
200
- 'UND_ERR_CONNECT',
201
- 'EPROTO',
202
- 'UND_ERR_DESTROYED',
203
- 'UND_ERR_CLOSED',
204
- 'ECONNABORTED',
205
- 'ENETRESET',
206
- 'ERR_STREAM_DESTROYED',
207
- 'ERR_HTTP2_STREAM_ERROR',
208
- 'ERR_HTTP2_SESSION_ERROR',
209
- 'ERR_HTTP2_INVALID_SESSION',
210
- 'ERR_SOCKET_CONNECTION_TIMEOUT',
211
- 'ERR_SSL_WRONG_VERSION_NUMBER',
212
- 'ERR_STREAM_PREMATURE_CLOSE',
213
- ]);
214
-
215
- // TLS record corruption on a flaky link or a meddling proxy. Node builds the
216
- // ERR_SSL_* code from the OpenSSL reason string, which differs across OpenSSL
217
- // versions (…SSLV3_ALERT_BAD_RECORD_MAC, …SSL/TLS_ALERT_BAD_RECORD_MAC,
218
- // …DECRYPTION_FAILED_OR_BAD_RECORD_MAC), so the stable suffix names the class.
219
- const TLS_RECORD_FAILURE_RE = /^ERR_SSL_[A-Z0-9_/]*BAD_RECORD_MAC$/i;
220
-
221
- /** True for a socket/TLS errno that describes a transient transport fault. */
222
- export function isTransientErrorCode(code) {
223
- const value = String(code || '');
224
- return TRANSIENT_ERROR_CODES.has(value) || TLS_RECORD_FAILURE_RE.test(value);
225
- }
226
-
227
219
  // Cursor's HTTP/2 bridge preserves provider-specific codes in `cursorCode`.
228
220
  // These codes all describe an incomplete transport turn, not a model verdict.
229
221
  // Replay permission remains fail-closed in the stream-outcome gate above.
@@ -342,9 +334,8 @@ export function isToolInputCut(err) {
342
334
  // The provider was never reached: name resolution, routing, refusal or the
343
335
  // connect handshake failed, so nothing was sent or received. Only this class
344
336
  // is worth waiting out for minutes — the identical request succeeds once the
345
- // network is back (a lift, a sleeping laptop, a router reboot), and the
346
- // reference client keeps a sampling turn alive until such a connection
347
- // recovers. A stream that dropped mid-response is not this class: it keeps
337
+ // network is back (a lift, a sleeping laptop, a router reboot), so a sampling
338
+ // turn is kept alive until such a connection recovers. A stream that dropped mid-response is not this class: it keeps
348
339
  // the short, bounded retry budget.
349
340
  const CONNECT_FAILURE_CODES = new Set([
350
341
  'ENOTFOUND',
@@ -382,9 +373,14 @@ export function isServerUnavailable(err) {
382
373
  if (!err || (typeof err !== 'object' && typeof err !== 'function')) return false;
383
374
  const chain = boundedCauseChain(err);
384
375
  if (chain.some(isExplicitUserAbortError)) return false;
376
+ // Typed kind first: an overload (any status) is this class; quota, billing,
377
+ // policy, auth, request refusals and rate limits never are.
378
+ const { kind } = providerErrorKind(err);
379
+ if (kind === 'overloaded') return true;
380
+ if (kind !== 'transient' && kind !== 'unknown') return false;
385
381
  const status = statusOfError(err);
386
382
  if (status) return status === 408 || (status >= 500 && status < 600 && !TERMINAL_EDGE_STATUSES.has(status));
387
- if (isRetryableWireErrorEvent(err)) return typedErrorCode(err) !== RATE_LIMIT_EXCEEDED;
383
+ if (isRetryableWireErrorEvent(err)) return true;
388
384
  return chain.some((item) => {
389
385
  const rpc = [item?.geminiStatus, item?.error?.status, typeof item?.status === 'string' ? item.status : ''];
390
386
  if (rpc.some((field) => GEMINI_TRANSIENT_RPC_CODES.has(String(field || '').toUpperCase()))) return true;
@@ -414,21 +410,11 @@ export function canFallbackNonStreaming(err, { signal } = {}) {
414
410
  // A cut mid tool-argument stream is replayed by the loop with a split-call
415
411
  // notice, never re-issued unchanged here.
416
412
  if (isToolInputCut(err)) return false;
413
+ // A provider-terminal verdict ends recovery; no re-issue of any shape.
414
+ if (boundedCauseChain(err).some((item) => item?.providerRecoveryTerminal === true)) return false;
417
415
  return classifyError(err) === 'transient' || outcome.stallObserved === true || outcome.truncatedStream === true;
418
416
  }
419
417
 
420
- export function boundedCauseChain(err) {
421
- const chain = [];
422
- const seen = new Set();
423
- let cursor = err;
424
- while (cursor && chain.length < MAX_CAUSE_CHAIN_DEPTH && !seen.has(cursor)) {
425
- chain.push(cursor);
426
- seen.add(cursor);
427
- cursor = cursor?.cause;
428
- }
429
- return chain;
430
- }
431
-
432
418
  export function isExplicitUserAbortError(err) {
433
419
  if (!err || (typeof err !== 'object' && typeof err !== 'function')) return false;
434
420
  if (err.name === 'AbortError' || err.name === 'APIUserAbortError' || err.code === 'ABORT_ERR') return true;
@@ -462,34 +448,10 @@ export function isCursorTransientTransportError(err) {
462
448
  // Patterns cover OpenAI ("maximum context length", "reduce the length"),
463
449
  // Anthropic ("prompt is too long"), and generic "input exceeds the context
464
450
  // window" phrasing. Match is case-insensitive over err.message.
465
- const CONTEXT_OVERFLOW_PATTERNS = [
466
- /input (?:length|tokens?) exceeds? the context window/i,
467
- /exceeds? the (?:maximum )?context (?:window|length)/i,
468
- /maximum context length/i,
469
- /context[_ ]length[_ ]exceeded/i,
470
- /prompt is too long/i,
471
- /reduce the length of (?:the )?(?:messages|input|prompt)/i,
472
- // Wordings other backends use for the same refusal, each tied to a context
473
- // or input-length noun so a tokens-per-minute rate limit never matches.
474
- /prompt too long/i, // z.ai, Ollama
475
- /prompt exceeds max length/i, // z.ai CN endpoint
476
- /input is too long for requested model/i, // Amazon Bedrock
477
- /input token count.*exceeds the maximum/i, // Google
478
- /request payload size exceeds the limit/i, // Google (400, byte-size limit)
479
- // A 413 re-wrapped by a proxy or aggregator without its status.
480
- /request entity too large/i,
481
- /request exceeds the maximum size/i,
482
- /maximum prompt length is \d+/i, // xAI
483
- /exceeds (?:the )?maximum allowed input length/i, // OpenRouter relays
484
- /is longer than the model'?s context length/i, // Together AI
485
- /exceeds the available context size/i, // llama.cpp server
486
- /greater than the context length/i, // LM Studio
487
- /context window exceeds limit/i, // MiniMax
488
- /exceeded model token limit/i, // Kimi
489
- /too large for model with \d+ maximum context length/i, // Mistral
490
- /range of input length should be/i, // DashScope / Qwen
491
- /model_context_window_exceeded/i, // z.ai finish reason surfaced as text
492
- ];
451
+ // Untyped byte-size wordings (no status, no code) keep routing here: an
452
+ // unlabelled proxy refusal is most often an oversized history.
453
+ const CONTEXT_OVERFLOW_PATTERNS = [...TOKEN_CONTEXT_OVERFLOW_PATTERNS, ...REQUEST_SIZE_PATTERNS];
454
+ const REQUEST_TOO_LARGE_KIND = 'request_too_large';
493
455
 
494
456
  /**
495
457
  * True when `err` is a context-window-exceeded provider rejection. Walks
@@ -502,89 +464,37 @@ const CONTEXT_OVERFLOW_PATTERNS = [
502
464
  */
503
465
  export function isContextOverflowError(err, _depth = 0) {
504
466
  if (!err || _depth > 2) return false;
505
- if (statusOfError(err) === 413) return true;
467
+ // A local fixed-overhead refusal (anywhere in the chain, at any recursion
468
+ // level) is never a provider overflow: compacting history cannot help it,
469
+ // whatever its text names.
470
+ if (isToolSurfaceExceedsContextError(err)) return false;
506
471
  const code = typedErrorCode(err);
507
472
  if (code && CONTEXT_OVERFLOW_CODES.has(code)) return true;
473
+ // A typed byte/media-size refusal (a size code, or HTTP 413 without a
474
+ // token-context code) is not a token-context overflow: compaction cannot
475
+ // shrink it, so only token-context wording may still qualify it.
476
+ const sizeTyped =
477
+ typeof err === 'object' &&
478
+ boundedCauseChain(err).some(
479
+ (item) => item && typeof item === 'object' && providerErrorKind(item, { text: false }).kind === REQUEST_TOO_LARGE_KIND
480
+ );
481
+ const patterns = sizeTyped ? TOKEN_CONTEXT_OVERFLOW_PATTERNS : CONTEXT_OVERFLOW_PATTERNS;
508
482
  const msg = (typeof err === 'string' ? err : err?.message) || '';
509
- if (msg && CONTEXT_OVERFLOW_PATTERNS.some((re) => re.test(msg))) return true;
483
+ if (msg && patterns.some((re) => re.test(msg))) return true;
510
484
  if (err.cause != null && err.cause !== err) return isContextOverflowError(err.cause, _depth + 1);
511
485
  if (err.response?.data != null) return isContextOverflowError(err.response.data, _depth + 1);
512
486
  return false;
513
487
  }
514
488
 
515
- export function headerValue(headers, name) {
516
- if (!headers) return null;
517
- const lower = name.toLowerCase();
518
- if (typeof headers.get === 'function') return headers.get(name) ?? headers.get(lower);
519
- for (const [key, value] of Object.entries(headers)) {
520
- if (String(key).toLowerCase() === lower) return Array.isArray(value) ? value[0] : value;
521
- }
522
- return null;
523
- }
524
-
525
- export function retryAfterMsFromError(err) {
526
- const headers = err?.headers || err?.response?.headers || err?.data?.responseHeaders || null;
527
- const retryAfterMs = headerValue(headers, 'retry-after-ms');
528
- if (retryAfterMs != null && retryAfterMs !== '') {
529
- const n = Number(retryAfterMs);
530
- if (Number.isFinite(n) && n >= 0) return n;
531
- }
532
- const retryAfter = headerValue(headers, 'retry-after');
533
- if (retryAfter != null && retryAfter !== '') {
534
- const seconds = Number(retryAfter);
535
- if (Number.isFinite(seconds) && seconds >= 0) return Math.ceil(seconds * 1000);
536
- const dateMs = Date.parse(String(retryAfter));
537
- if (!Number.isNaN(dateMs)) return Math.max(0, dateMs - Date.now());
538
- }
539
- // Google RPC RetryInfo encodes retryDelay as a protobuf Duration. Preserve
540
- // the same precedence as Retry-After: a server-provided retry window means
541
- // RESOURCE_EXHAUSTED is request-local, not a permanent quota refusal.
542
- const detailLists = [err?.details, err?.error?.details, err?.data?.error?.details];
543
- for (const details of detailLists) {
544
- if (!Array.isArray(details)) continue;
545
- for (const detail of details) {
546
- const delay = detail?.retryDelay;
547
- if (typeof delay === 'string') {
548
- const match = delay.trim().match(/^(\d+(?:\.\d+)?)s$/);
549
- if (match) return Math.ceil(Number(match[1]) * 1000);
550
- } else if (delay && typeof delay === 'object') {
551
- const seconds = Number(delay.seconds || 0);
552
- const nanos = Number(delay.nanos || 0);
553
- const ms = seconds * 1000 + nanos / 1_000_000;
554
- if (Number.isFinite(ms) && ms >= 0) return Math.ceil(ms);
555
- }
556
- }
557
- }
558
- const resetHeader = headerValue(headers, ANTHROPIC_RESET_HEADER);
559
- if (resetHeader != null && resetHeader !== '') {
560
- const resetUnixSec = Number(resetHeader);
561
- if (Number.isFinite(resetUnixSec) && resetUnixSec > 0) {
562
- const delayMs = Math.ceil(resetUnixSec * 1000 - Date.now());
563
- if (delayMs > 0) return Math.min(delayMs, ANTHROPIC_RESET_CAP_MS);
564
- }
565
- }
566
- // Codex parses the server-supplied window from a TYPED rate_limit_exceeded
567
- // payload. Message text never decides whether to retry — only how long to
568
- // wait after the typed code is already in hand. Headers / RetryInfo win.
569
- if (typedErrorCode(err) === RATE_LIMIT_EXCEEDED) {
570
- const delay = rateLimitRetryAfterMsFromMessage(err);
571
- if (delay != null) return delay;
572
- }
573
- return null;
574
- }
575
-
489
+ /**
490
+ * True for an explicit quota / plan / billing refusal (providerErrorKind
491
+ * quota_exhausted, entitlement or billing). No wait recovers it, so retry
492
+ * layers never replay it, even when the server attached a Retry-After.
493
+ * RESOURCE_EXHAUSTED with a 429, retry advice or a per-minute scope is a
494
+ * request-local rate limit instead.
495
+ */
576
496
  export function isPermanentQuotaError(err) {
577
- const status = statusOfError(err);
578
- // Gemini uses RESOURCE_EXHAUSTED for both daily quota and per-minute
579
- // rate limits. A 429 is request-local (Google/LiteLLM retry); without a
580
- // 429 the same code stays a deterministic quota refusal.
581
- const permanentCodes = new Set(['insufficient_quota', 'quota_exceeded']);
582
- if (status !== 429) permanentCodes.add('resource_exhausted');
583
- for (const item of boundedCauseChain(err)) {
584
- const codes = [item?.code, item?.error?.code];
585
- if (codes.some((code) => permanentCodes.has(String(code || '').toLowerCase()))) return true;
586
- }
587
- return false;
497
+ return QUOTA_KINDS.has(providerErrorKind(err).kind);
588
498
  }
589
499
 
590
500
  // ── Wire error events: default-retry with a fatal-code deny-list ────────────
@@ -595,7 +505,7 @@ export function isPermanentQuotaError(err) {
595
505
  // server_error, server_is_overloaded, slow_down, or an event with no code at
596
506
  // all — is a server-side fault and is retried under the bounded budgets
597
507
  // (observed live 2026-08-11: two turns failed on typed `server_error`
598
- // response.failed events that every reference implementation retries).
508
+ // response.failed events that are server-side faults).
599
509
  export const WIRE_ERROR_FATAL_CODES = new Set([
600
510
  'context_length_exceeded',
601
511
  'context_window_exceeded',
@@ -614,17 +524,26 @@ export const WIRE_ERROR_FATAL_CODES = new Set([
614
524
  'permission_error',
615
525
  'permission_denied',
616
526
  'billing_not_active',
527
+ // Billing / spend refusals.
528
+ 'credit_balance_exhausted',
529
+ 'organization_spend_limit_exceeded',
530
+ 'project_spend_limit_exceeded',
531
+ 'organization_usage_limit_exceeded',
532
+ 'billing_hard_limit_reached',
533
+ 'payment_required',
534
+ // Policy refusals.
535
+ 'cyber_policy_violation',
536
+ 'bio_policy_violation',
537
+ 'misalignment_policy_violation',
538
+ 'content_policy_violation',
539
+ 'content_filter',
540
+ // Flex tier capacity: the same request at the same tier is refused again.
541
+ 'flex_unavailable',
542
+ // Byte/media size and token context.
543
+ 'request_too_large',
544
+ 'model_context_window_exceeded',
617
545
  ]);
618
546
 
619
- export function typedErrorCode(err) {
620
- const failed = err?.responseFailed;
621
- const detail = failed?.response?.error || failed?.error || err?.providerError || failed || null;
622
- for (const field of [detail?.code, detail?.type, err?.providerErrorCode, err?.code, err?.error?.code]) {
623
- if (typeof field === 'string' && field.trim()) return field.trim().toLowerCase();
624
- }
625
- return '';
626
- }
627
-
628
547
  /**
629
548
  * True when the typed wire/SDK code is previous_response_not_found.
630
549
  * Callers drop lastResponseId / previous_response_id and re-issue a full frame.
@@ -657,30 +576,15 @@ export function isStaleKeepAliveError(err) {
657
576
  });
658
577
  }
659
578
 
660
- const RATE_LIMIT_RETRY_AFTER_RE = /try again in\s*(\d+(?:\.\d+)?)\s*(ms|s|seconds?)\b/i;
661
-
662
- function rateLimitRetryAfterMsFromMessage(err) {
663
- const failed = err?.responseFailed;
664
- const detail = failed?.response?.error || failed?.error || err?.providerError || err?.error || null;
665
- const messages = [detail?.message, err?.message];
666
- for (const message of messages) {
667
- if (typeof message !== 'string' || !message) continue;
668
- const match = message.match(RATE_LIMIT_RETRY_AFTER_RE);
669
- if (!match) continue;
670
- const value = Number(match[1]);
671
- if (!Number.isFinite(value) || value < 0) continue;
672
- const unit = String(match[2] || '').toLowerCase();
673
- return unit === 'ms' ? Math.ceil(value) : Math.ceil(value * 1000);
674
- }
675
- return null;
676
- }
677
-
678
579
  // 'transient' | 'permanent' for errors born from a provider wire error event;
679
580
  // null for everything else (no blanket retry for untyped local failures).
581
+ // A fatal code or a deterministic kind (quota, billing, plan, policy, auth,
582
+ // permission, context, size) outranks any numeric 5xx the event carries.
680
583
  function classifyWireErrorEvent(err) {
681
584
  if (!err || (err.responseFailed == null && err.providerWireError !== true)) return null;
682
585
  const code = typedErrorCode(err);
683
586
  if (code && WIRE_ERROR_FATAL_CODES.has(code)) return 'permanent';
587
+ if (DETERMINISTIC_KINDS.has(providerErrorKind(err, { text: false }).kind)) return 'permanent';
684
588
  return 'transient';
685
589
  }
686
590
 
@@ -696,7 +600,7 @@ export function isRetryableWireErrorEvent(err) {
696
600
  }
697
601
 
698
602
  /**
699
- * Grok Build StreamError: a mid-stream wire fault is retryable even when the
603
+ * Mid-stream wire error event: a mid-stream wire fault is retryable even when the
700
604
  * envelope type is invalid_request_error, unless a typed 4xx status or a
701
605
  * deterministic refusal code (quota/context/auth) is present.
702
606
  */
@@ -50,6 +50,7 @@ export {
50
50
  ANTHROPIC_RETRY_BACKOFF_MS,
51
51
  ANTHROPIC_RETRY_JITTER_RATIO,
52
52
  AnthropicFallbackTriggeredError,
53
+ ModelFallbackTriggeredError,
53
54
  STREAM_STALL_RETRY_BUDGET_MS,
54
55
  anthropicMaxAttempts,
55
56
  anthropicRequestTimeoutMs,
@@ -71,6 +72,7 @@ export {
71
72
  createStreamSafetyStamps,
72
73
  emitProviderRetryStage,
73
74
  isProviderRecoveryExhausted,
75
+ isProviderRecoveryTerminal,
74
76
  markProviderRecoveryExhausted,
75
77
  retryDelayLabel,
76
78
  withRetry,