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
@@ -14,13 +14,16 @@ import {
14
14
  ANTHROPIC_RETRY_JITTER_RATIO,
15
15
  anthropicMaxAttempts,
16
16
  anthropicRequestTimeoutMs,
17
+ AnthropicFallbackTriggeredError,
17
18
  emitProviderRetryStage,
18
19
  withRetry,
19
- retryAfterMsFromError,
20
20
  retryDelayLabel,
21
21
  } from './retry-classifier.mjs';
22
+ import { ANTHROPIC_MAX_CONSECUTIVE_529 } from './retry-backoff.mjs';
22
23
  import { PROVIDER_FIRST_BYTE_TIMEOUT_MS, createTimeoutSignal } from '../stall-policy.mjs';
23
- import { noteFastModeCapacityError } from './anthropic-fast-mode.mjs';
24
+ import { fastModeDowngraded, noteFastModeCapacityError } from './anthropic-fast-mode.mjs';
25
+ import { adjustMaxTokensForContextOverflow } from './anthropic-max-tokens-recovery.mjs';
26
+ import { applyAnthropicErrorContract, retryAfterMsFromHeaders } from './anthropic-error-contract.mjs';
24
27
  import { noteRequestServiceTier } from '../../../shared/llm/usage-context.mjs';
25
28
  import { notifyCurrentAnthropicRateLimit } from './admission-scheduler.mjs';
26
29
 
@@ -78,12 +81,61 @@ export function armFirstByteWatchdog(streamController, midState) {
78
81
  * @param {object} deps.params the streaming request body (mutated on fast-pool de-latch)
79
82
  * @param {object|null} deps.requestHeaders per-call beta/extra headers
80
83
  * @param {AbortSignal|null} deps.totalSignal session-lifetime pass-through
84
+ * @param {{ state: { consecutive529Errors: number } }|null} [deps.overload] the send's shared overload counter
81
85
  */
82
- export function createAnthropicApiTransport({ client, label, opts, useModel, params, requestHeaders, totalSignal }) {
86
+ export function createAnthropicApiTransport({
87
+ client,
88
+ label,
89
+ opts,
90
+ useModel,
91
+ params,
92
+ requestHeaders,
93
+ totalSignal,
94
+ overload = null,
95
+ }) {
83
96
  const requestOptions = (attemptSignal) => ({
84
97
  signal: attemptSignal,
85
98
  ...(requestHeaders ? { headers: requestHeaders } : {}),
86
99
  });
100
+ // The SDK throws a non-2xx before `.asResponse()` resolves, so an HTTP
101
+ // failure arrives as an APIError rather than a Response. Stamp the
102
+ // provider-boundary error contract on it (status, lowercased error type as
103
+ // `code`, preserved headers, uncapped retryAfterMs / resetAt).
104
+ const annotateHttpFailure = (err) => {
105
+ if (err && typeof err === 'object' && Number(err.status || err.httpStatus || 0) > 0) {
106
+ applyAnthropicErrorContract(err, { status: err.status || err.httpStatus, headers: err.headers });
107
+ }
108
+ return err;
109
+ };
110
+ // A fast-pool refusal (or a "Fast mode is not enabled" 400) says nothing
111
+ // about standard-speed capacity: drop `speed` and let the caller replay at
112
+ // once instead of waiting out a window that only the fast pool owns.
113
+ const dropFastSpeedAfter = (body, err) => {
114
+ if (body.speed !== 'fast') return false;
115
+ if (!fastModeDowngraded(noteFastModeCapacityError(err, { fast: true }))) return false;
116
+ delete body.speed;
117
+ return true;
118
+ };
119
+ // In-attempt body repairs, each replayed once: drop speed after a fast-pool
120
+ // refusal, and shrink max_tokens after the "input length and max_tokens
121
+ // exceed context limit" 400.
122
+ const withBodyRecovery = (body, attempt) => async (ctx) => {
123
+ let speedDropped = false;
124
+ let tokensAdjusted = false;
125
+ for (;;) {
126
+ try {
127
+ return await attempt(ctx);
128
+ } catch (err) {
129
+ if (!speedDropped && dropFastSpeedAfter(body, err)) {
130
+ speedDropped = true;
131
+ } else if (!tokensAdjusted && adjustMaxTokensForContextOverflow(body, err?.status, err?.message)) {
132
+ tokensAdjusted = true;
133
+ } else {
134
+ throw err;
135
+ }
136
+ }
137
+ }
138
+ };
87
139
  // Initial-response retry policy shared by the streaming request and the
88
140
  // non-streaming fallback.
89
141
  const retryPolicy = (signal, perAttemptLabel, recoveryOwner) => ({
@@ -95,23 +147,27 @@ export function createAnthropicApiTransport({ client, label, opts, useModel, par
95
147
  perAttemptTimeoutMs: anthropicRequestTimeoutMs(),
96
148
  perAttemptLabel,
97
149
  provider: 'anthropic',
150
+ // This transport honors the positive x-should-retry override.
151
+ honorShouldRetryTrue: true,
98
152
  recoveryOwner,
99
153
  retry529: opts.retry529,
100
154
  model: useModel,
101
155
  fallbackModel: opts._fallbackTriggered ? undefined : opts.fallbackModel,
156
+ // One overload counter for the send: SSE overloads count toward the same
157
+ // limit as request-loop 529s.
158
+ overloadState: overload?.state,
159
+ overloadFallbackAfter: ANTHROPIC_MAX_CONSECUTIVE_529,
160
+ stopAfterRepeated529: overload?.stopAfterRepeated529 === true,
102
161
  });
103
162
 
104
- const requestStreamingResponse = () =>
105
- withRetry(
106
- async ({ signal: attemptSignal }) => {
107
- noteRequestServiceTier(params.speed);
163
+ const requestStreamingResponse = async () => {
164
+ const attempt = async ({ signal: attemptSignal }) => {
165
+ noteRequestServiceTier(params.speed);
166
+ try {
108
167
  const res = await client.messages.create(params, requestOptions(attemptSignal)).asResponse();
109
168
  if (!res.ok) {
110
169
  const text = await res.text().catch(() => '');
111
170
  const err = new Error(`Anthropic API ${res.status}: ${text.slice(0, 200)}`);
112
- err.status = res.status;
113
- err.httpStatus = res.status;
114
- err.initialResponseError = true;
115
171
  // Carry response headers so withRetry can honor a
116
172
  // short Retry-After and upstream can read quota hints.
117
173
  err.headers = res.headers;
@@ -120,48 +176,55 @@ export function createAnthropicApiTransport({ client, label, opts, useModel, par
120
176
  // output/tool exposure, so the request-local
121
177
  // withRetry loop may retry it with jitter.
122
178
  if (res.status === 429) {
123
- const retryAfterMs = retryAfterMsFromError({
124
- headers: res.headers,
125
- response: { headers: res.headers },
126
- });
127
179
  err.name = 'ProviderQuotaError';
128
- err.code = 'PROVIDER_QUOTA';
129
- err.retryAfterMs = retryAfterMs;
180
+ err.retryAfterMs = retryAfterMsFromHeaders(res.headers);
130
181
  err.providerQuota = true;
131
182
  err.quotaExceeded = true;
132
183
  }
133
- throw err;
184
+ throw applyAnthropicErrorContract(err, { status: res.status, headers: res.headers, bodyText: text });
134
185
  }
135
186
  if (!res.body) {
136
187
  throw new Error('Anthropic streaming response has no body');
137
188
  }
138
189
  return res;
139
- },
140
- {
190
+ } catch (err) {
191
+ throw annotateHttpFailure(err);
192
+ }
193
+ };
194
+ try {
195
+ return await withRetry(withBodyRecovery(params, attempt), {
141
196
  ...retryPolicy(totalSignal, `${label} Anthropic streaming response`, `${label}-initial-response`),
142
- onRetry: ({ attempt, maxAttempts, lastErr, delayMs, delayReason }) => {
143
- emitProviderRetryStage(opts.onStageChange, { attempt: attempt + 1, maxAttempts, lastErr, delayMs });
144
- // Long/unknown fast-pool window: replay at
145
- // standard speed rather than waiting it out.
146
- if (params?.speed === 'fast' && noteFastModeCapacityError(lastErr, { fast: true }) !== 'retry-fast') {
147
- delete params.speed;
148
- }
197
+ onRetry: ({ attempt: retryNo, maxAttempts, lastErr, delayMs, delayReason }) => {
198
+ emitProviderRetryStage(opts.onStageChange, { attempt: retryNo + 1, maxAttempts, lastErr, delayMs });
149
199
  const status = Number(lastErr?.httpStatus || lastErr?.status || lastErr?.response?.status || 0);
150
200
  if (status === 429) notifyCurrentAnthropicRateLimit(lastErr);
151
201
  const delayLabel = retryDelayLabel(delayMs, delayReason);
152
202
  process.stderr.write(
153
- `[${label}] retry attempt ${attempt + 1} after ${lastErr?.message || lastErr?.code || 'transient error'}${delayLabel}\n`
203
+ `[${label}] retry attempt ${retryNo + 1} after ${lastErr?.message || lastErr?.code || 'transient error'}${delayLabel}\n`
154
204
  );
155
205
  },
206
+ });
207
+ } catch (err) {
208
+ // Whatever escapes withRetry failed before any stream existed and has
209
+ // already spent the request-level budget: mark it so mid-stream
210
+ // recovery never grants it a second, SSE-sized retry budget.
211
+ if (err && typeof err === 'object' && !(err instanceof AnthropicFallbackTriggeredError)) {
212
+ err.initialResponseError = true;
156
213
  }
157
- );
214
+ throw err;
215
+ }
216
+ };
158
217
 
159
218
  const requestNonStreamingMessage = (nonStreamingParams, signal) =>
160
219
  withRetry(
161
- async ({ signal: attemptSignal }) => {
220
+ withBodyRecovery(nonStreamingParams, async ({ signal: attemptSignal }) => {
162
221
  noteRequestServiceTier(nonStreamingParams.speed);
163
- return client.messages.create(nonStreamingParams, requestOptions(attemptSignal));
164
- },
222
+ try {
223
+ return await client.messages.create(nonStreamingParams, requestOptions(attemptSignal));
224
+ } catch (err) {
225
+ throw annotateHttpFailure(err);
226
+ }
227
+ }),
165
228
  {
166
229
  ...retryPolicy(signal, `${label} Anthropic non-streaming fallback`, `${label}-nonstreaming-request`),
167
230
  onRetry: ({ attempt, maxAttempts, lastErr, delayMs }) =>
@@ -0,0 +1,98 @@
1
+ /**
2
+ * anthropic-error-contract.mjs — the fields every error thrown at an Anthropic
3
+ * provider boundary carries, so the shared core never has to re-derive them
4
+ * from message text:
5
+ *
6
+ * status / httpStatus the HTTP status
7
+ * code the lowercased Anthropic error type (`rate_limit_error`,
8
+ * `overloaded_error`, ...); a 413 is always
9
+ * `request_too_large` (a byte/media size refusal), which
10
+ * stays distinct from a 400 `invalid_request_error`
11
+ * "prompt is too long" (a token-count refusal)
12
+ * headers the response headers, preserved as received
13
+ * retryAfterMs the server's Retry-After / retry-after-ms window, uncapped
14
+ * resetAt epoch ms of anthropic-ratelimit-unified-reset, uncapped
15
+ */
16
+ import { headerValue, retryAfterMsFromError } from './retry-classification.mjs';
17
+
18
+ const RESET_HEADER = 'anthropic-ratelimit-unified-reset';
19
+ const REQUEST_TOO_LARGE = 'request_too_large';
20
+
21
+ // Anthropic's documented error-type enumeration by status, used only when the
22
+ // body names no type of its own.
23
+ const STATUS_ERROR_TYPE = new Map([
24
+ [400, 'invalid_request_error'],
25
+ [401, 'authentication_error'],
26
+ [403, 'permission_error'],
27
+ [404, 'not_found_error'],
28
+ [409, 'conflict_error'],
29
+ [413, REQUEST_TOO_LARGE],
30
+ [429, 'rate_limit_error'],
31
+ [500, 'api_error'],
32
+ [504, 'timeout_error'],
33
+ [529, 'overloaded_error'],
34
+ ]);
35
+
36
+ const BODY_TYPE_RE = /"error"\s*:\s*\{\s*"type"\s*:\s*"([A-Za-z_]+)"/;
37
+
38
+ function present(value) {
39
+ return value != null && value !== '';
40
+ }
41
+
42
+ function lowered(value) {
43
+ return typeof value === 'string' && value.trim() && value.trim() !== 'error' ? value.trim().toLowerCase() : '';
44
+ }
45
+
46
+ /** The lowercased error type named by an Anthropic error body (JSON text or parsed object). */
47
+ export function anthropicErrorTypeFromBody(body) {
48
+ if (body && typeof body === 'object') return lowered((body.error && body.error.type) || body.type);
49
+ const match = BODY_TYPE_RE.exec(String(body || ''));
50
+ return match ? lowered(match[1]) : '';
51
+ }
52
+
53
+ /** Retry-After / retry-after-ms in ms, uncapped; null when the server sent neither. */
54
+ export function retryAfterMsFromHeaders(headers) {
55
+ if (!present(headerValue(headers, 'retry-after-ms')) && !present(headerValue(headers, 'retry-after'))) return null;
56
+ return retryAfterMsFromError({ headers });
57
+ }
58
+
59
+ /** Epoch ms of the unified rate-limit reset header, uncapped; null when absent or past. */
60
+ export function resetAtFromHeaders(headers) {
61
+ const raw = headerValue(headers, RESET_HEADER);
62
+ if (!present(raw)) return null;
63
+ const seconds = Number(raw);
64
+ return Number.isFinite(seconds) && seconds > 0 ? Math.ceil(seconds * 1000) : null;
65
+ }
66
+
67
+ /**
68
+ * Stamp the contract onto `err`. Existing `headers` and a finite
69
+ * `retryAfterMs` are preserved. `type` is the wire error type when the caller
70
+ * already parsed one; otherwise it is read from `bodyText` (or err.error, the
71
+ * SDK's parsed body, or err.message) and finally from the status.
72
+ */
73
+ export function applyAnthropicErrorContract(err, { status, headers, type = '', bodyText = '' } = {}) {
74
+ if (!err || typeof err !== 'object') return err;
75
+ const httpStatus = Number(status || err.httpStatus || err.status || 0) || 0;
76
+ if (httpStatus) {
77
+ err.status = httpStatus;
78
+ err.httpStatus = httpStatus;
79
+ const wireType =
80
+ lowered(type) ||
81
+ anthropicErrorTypeFromBody(bodyText) ||
82
+ anthropicErrorTypeFromBody(err.error) ||
83
+ anthropicErrorTypeFromBody(err.message) ||
84
+ STATUS_ERROR_TYPE.get(httpStatus) ||
85
+ '';
86
+ const code = httpStatus === 413 ? REQUEST_TOO_LARGE : wireType;
87
+ if (code) err.code = code;
88
+ }
89
+ if (!err.headers && headers) err.headers = headers;
90
+ const effectiveHeaders = err.headers || headers || null;
91
+ if (!(err.retryAfterMs != null && Number.isFinite(Number(err.retryAfterMs)))) {
92
+ const retryAfterMs = retryAfterMsFromHeaders(effectiveHeaders);
93
+ if (retryAfterMs != null) err.retryAfterMs = retryAfterMs;
94
+ }
95
+ const resetAt = resetAtFromHeaders(effectiveHeaders);
96
+ if (resetAt != null) err.resetAt = resetAt;
97
+ return err;
98
+ }
@@ -6,7 +6,7 @@
6
6
  // cache, because the retry after the wait carries a different speed anyway.
7
7
  // The reference client's rule: a SHORT server window is worth waiting for at
8
8
  // fast speed (the cache prefix survives), anything longer drops to standard
9
- // speed for a cooldown. An explicit "overage billing unavailable" header is
9
+ // speed for a cooldown (reference thresholds: <20s keeps fast; otherwise\n// max(Retry-After ?? 30min, 10min)). An explicit "overage billing unavailable" header is
10
10
  // terminal for the process — no cooldown can make paid overage appear.
11
11
  //
12
12
  // State is process-wide because the capacity pool is per-account, not per
@@ -14,23 +14,28 @@
14
14
  // sessions hammering it.
15
15
 
16
16
  import { headerValue } from './retry-classification.mjs';
17
+ import { retryAfterMsFromHeaders } from './anthropic-error-contract.mjs';
17
18
 
18
19
  // Server-declared reason header for a fast-mode rejection caused by missing
19
20
  // overage billing (matches the reference client's header name).
20
21
  const OVERAGE_DISABLED_HEADER = 'anthropic-ratelimit-unified-overage-disabled-reason';
21
- // Body-only form of the same rejection ("Usage credits are required for fast
22
- // mode."), sent as a 429 rate_limit_error without the header above.
23
- const CREDITS_REQUIRED_PATTERN = /usage credits are required for fast mode/i;
24
- const CREDITS_REQUIRED_REASON = 'usage_credits_required';
22
+ // Reasons that mean the wallet is empty / capped for now rather than that
23
+ // overage can never exist: the request drops to standard speed, but fast mode
24
+ // is not switched off (the reference client keeps its setting for these).
25
+ const TRANSIENT_OVERAGE_REASONS = new Set(['org_level_disabled_until', 'out_of_credits']);
26
+ // A 400 from an account/endpoint that cannot serve fast mode at all. The same
27
+ // request succeeds at standard speed, and no cooldown makes it succeed fast.
28
+ const NOT_ENABLED_PATTERN = /fast mode is not enabled/i;
29
+ const NOT_ENABLED_REASON = 'fast_mode_not_enabled';
25
30
 
26
31
  // A Retry-After under this bound is short enough that waiting keeps fast mode
27
32
  // (and its cache prefix) worthwhile.
28
- const SHORT_RETRY_THRESHOLD_MS = 10_000;
33
+ const SHORT_RETRY_THRESHOLD_MS = 20_000;
29
34
  // Cooldown floor: without it a 1s window would flip fast mode on and off every
30
35
  // turn, which costs more in cache misses than the downgrade saves.
31
- const MIN_COOLDOWN_MS = 60_000;
36
+ const MIN_COOLDOWN_MS = 600_000;
32
37
  // Applied when the server gives no window at all.
33
- const DEFAULT_COOLDOWN_MS = 300_000;
38
+ const DEFAULT_COOLDOWN_MS = 1_800_000;
34
39
 
35
40
  let _cooldownUntilMs = 0;
36
41
  let _disabledReason = null;
@@ -62,23 +67,23 @@ export function fastModeDisabledReason() {
62
67
  export function noteFastModeCapacityError(err, { fast = false, now = Date.now() } = {}) {
63
68
  if (!fast) return 'ignored';
64
69
  const status = Number(err?.httpStatus || err?.status || err?.response?.status || 0);
70
+ if (status === 400 && NOT_ENABLED_PATTERN.test(String(err?.message || ''))) {
71
+ _disabledReason = NOT_ENABLED_REASON;
72
+ return 'disabled';
73
+ }
65
74
  if (status !== 429 && status !== 529) return 'ignored';
66
75
 
67
76
  const headers = err?.headers || err?.response?.headers || err?.data?.responseHeaders || null;
68
77
  const overageReason = headerValue(headers, OVERAGE_DISABLED_HEADER);
69
- if (overageReason != null && String(overageReason) !== '') {
70
- _disabledReason = String(overageReason);
71
- return 'disabled';
72
- }
73
- // Same terminal condition reported only in the error body: the account has
74
- // no usage credits for fast mode, so no cooldown can make it succeed.
75
- if (CREDITS_REQUIRED_PATTERN.test(String(err?.message || ''))) {
76
- _disabledReason = CREDITS_REQUIRED_REASON;
78
+ // The header's presence (even empty) is the signal, as in the reference client.
79
+ if (overageReason != null) {
80
+ if (TRANSIENT_OVERAGE_REASONS.has(String(overageReason))) return 'downgrade';
81
+ _disabledReason = String(overageReason) || 'overage_unavailable';
77
82
  return 'disabled';
78
83
  }
79
84
 
80
- const retryAfterMs = Number(err?.retryAfterMs);
81
- const hasWindow = Number.isFinite(retryAfterMs) && retryAfterMs >= 0;
85
+ const retryAfterMs = serverWindowMs(err);
86
+ const hasWindow = retryAfterMs != null;
82
87
  if (hasWindow && retryAfterMs < SHORT_RETRY_THRESHOLD_MS) return 'retry-fast';
83
88
 
84
89
  const cooldownMs = Math.max(hasWindow ? retryAfterMs : DEFAULT_COOLDOWN_MS, MIN_COOLDOWN_MS);
@@ -86,6 +91,22 @@ export function noteFastModeCapacityError(err, { fast = false, now = Date.now()
86
91
  return 'downgrade';
87
92
  }
88
93
 
94
+ /** True when the decision means the caller must drop `speed` before replaying. */
95
+ export function fastModeDowngraded(decision) {
96
+ return decision === 'downgrade' || decision === 'disabled';
97
+ }
98
+
99
+ // The server's Retry-After window: an explicit err.retryAfterMs, else the
100
+ // Retry-After headers. The unified-reset header is deliberately not a window
101
+ // here (the reference client reads Retry-After only). null when none.
102
+ function serverWindowMs(err) {
103
+ const explicit = err?.retryAfterMs;
104
+ if (explicit != null && explicit !== '' && Number.isFinite(Number(explicit)) && Number(explicit) >= 0) {
105
+ return Number(explicit);
106
+ }
107
+ return retryAfterMsFromHeaders(err?.headers || err?.response?.headers || err?.data?.responseHeaders || null);
108
+ }
109
+
89
110
  /** Manual re-enable (user action) and test seam. */
90
111
  export function clearFastModeCooldown() {
91
112
  _cooldownUntilMs = 0;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * anthropic-max-tokens-recovery.mjs — the two max_tokens adjustments the
3
+ * reference client makes (withRetry.ts / claude.ts):
4
+ *
5
+ * - a 400 "input length and `max_tokens` exceed context limit: A + B > C" is
6
+ * answered by shrinking max_tokens to what the context still has room for
7
+ * (1000-token safety buffer, 3000-token floor, thinking budget + 1 minimum)
8
+ * and replaying; with less than the floor available the error surfaces.
9
+ * - the non-streaming replay caps max_tokens at 64000 (the API's long-request
10
+ * boundary) and keeps thinking.budget_tokens below it.
11
+ */
12
+
13
+ export const FLOOR_OUTPUT_TOKENS = 3000;
14
+ export const CONTEXT_SAFETY_BUFFER_TOKENS = 1000;
15
+ export const MAX_NON_STREAMING_TOKENS = 64_000;
16
+
17
+ const OVERFLOW_RE = /input length and `max_tokens` exceed context limit: (\d+) \+ (\d+) > (\d+)/;
18
+
19
+ /** `{ inputTokens, maxTokens, contextLimit }` for the exact 400, else null. */
20
+ export function parseMaxTokensContextOverflow(status, message) {
21
+ if (Number(status) !== 400) return null;
22
+ const match = OVERFLOW_RE.exec(String(message || ''));
23
+ if (!match) return null;
24
+ const [inputTokens, maxTokens, contextLimit] = match.slice(1).map((value) => Number.parseInt(value, 10));
25
+ return [inputTokens, maxTokens, contextLimit].every(Number.isFinite) ? { inputTokens, maxTokens, contextLimit } : null;
26
+ }
27
+
28
+ const thinkingBudget = (body) =>
29
+ body?.thinking?.type === 'enabled' && Number(body.thinking.budget_tokens) > 0 ? Number(body.thinking.budget_tokens) : 0;
30
+
31
+ /**
32
+ * Shrink `body.max_tokens` to fit the reported context. Returns true when the
33
+ * body was adjusted and is worth replaying.
34
+ */
35
+ export function adjustMaxTokensForContextOverflow(body, status, message) {
36
+ const overflow = parseMaxTokensContextOverflow(status, message);
37
+ if (!overflow || !body) return false;
38
+ const available = Math.max(0, overflow.contextLimit - overflow.inputTokens - CONTEXT_SAFETY_BUFFER_TOKENS);
39
+ if (available < FLOOR_OUTPUT_TOKENS) return false;
40
+ body.max_tokens = Math.max(FLOOR_OUTPUT_TOKENS, available, thinkingBudget(body) + 1);
41
+ return true;
42
+ }
43
+
44
+ /** Cap a non-streaming body in place (max_tokens and the thinking budget). */
45
+ export function capForNonStreaming(body) {
46
+ if (!body || !(Number(body.max_tokens) > MAX_NON_STREAMING_TOKENS)) return body;
47
+ body.max_tokens = MAX_NON_STREAMING_TOKENS;
48
+ if (thinkingBudget(body)) {
49
+ body.thinking = {
50
+ ...body.thinking,
51
+ budget_tokens: Math.min(body.thinking.budget_tokens, MAX_NON_STREAMING_TOKENS - 1),
52
+ };
53
+ }
54
+ return body;
55
+ }
@@ -4,29 +4,21 @@
4
4
  //
5
5
  // Resolution order:
6
6
  // 1. MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS env override, if set to a positive
7
- // int, wins outright (returned as the safety cap itself).
7
+ // int, wins, capped by the known model maximum when there is one.
8
8
  // 2. Catalog outputTokens for the model id (trusted over hardcoded
9
9
  // heuristics when present — the API reports real per-model limits),
10
- // clamped to [MAX_TOKENS_FLOOR, safetyCap].
11
- // 3. Static per-model table / family heuristic fallback when the catalog
12
- // has no entry for this model, also capped at the safety cap.
10
+ // clamped to safetyCap (never raised: a declared limit is a ceiling).
11
+ // 3. The shared model catalog's outputTokens for the model (cached roster /
12
+ // LiteLLM / models.dev), same clamp.
13
+ // 4. The pre-catalog family limits for a model no catalog describes, else
14
+ // the floor.
15
+
16
+ import { getModelMetadataSync } from './model-catalog.mjs';
13
17
 
14
18
  const MAX_TOKENS_FLOOR = 8192;
15
19
  const DEFAULT_SAFETY_CAP = 65536;
16
20
  const ENV_VAR = 'MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS';
17
21
 
18
- // Per-model max_tokens when the model id is explicitly listed. New models
19
- // (e.g., Sonnet 4.7) won't match a specific entry and fall through to the
20
- // family-based heuristic below. Conservative defaults — model may support
21
- // more but we'd rather stay within safe bounds.
22
- const MAX_TOKENS = {
23
- 'claude-opus-4-8': 65536,
24
- 'claude-opus-4-7': 65536,
25
- 'claude-opus-4-6': 65536,
26
- 'claude-sonnet-4-6': 16384,
27
- 'claude-haiku-4-5-20251001': 8192,
28
- };
29
-
30
22
  // Strict-positive env override parsing. Invalid values ("0", negatives,
31
23
  // garbage, whitespace) are treated as UNSET — not as "use the default cap
32
24
  // outright" — so catalog/fallback still decide for low-cap models. Raw env
@@ -39,11 +31,18 @@ function envAnthropicMaxOutputOverride() {
39
31
  return Math.floor(n);
40
32
  }
41
33
 
42
- // Static per-model table + family heuristic, used when the catalog has no
43
- // entry for this model id. Sonnet 5+ ships a much larger output budget than
44
- // the legacy 4.x line (this is the claude-sonnet-5 fix: 16384 was starving
45
- // visible output once extended thinking ate into the same hard cap). Keep
46
- // sonnet-4-x conservative at 16384; only bump 5+.
34
+ // Last resort when no catalog describes the model: the limits known before
35
+ // the catalogs existed. Sonnet 5+ ships a much larger output budget than the
36
+ // legacy 4.x line (16384 starved visible output once extended thinking ate
37
+ // into the same hard cap). Unknown families stay at the floor.
38
+ const MAX_TOKENS = {
39
+ 'claude-opus-4-8': 65536,
40
+ 'claude-opus-4-7': 65536,
41
+ 'claude-opus-4-6': 65536,
42
+ 'claude-sonnet-4-6': 16384,
43
+ 'claude-haiku-4-5-20251001': 8192,
44
+ };
45
+
47
46
  function fallbackAnthropicMaxTokens(model) {
48
47
  if (MAX_TOKENS[model]) return MAX_TOKENS[model];
49
48
  const id = String(model || '').toLowerCase();
@@ -52,27 +51,39 @@ function fallbackAnthropicMaxTokens(model) {
52
51
  const sonnetVersion = id.match(/^claude-sonnet-(\d+)/);
53
52
  if (sonnetVersion) return Number(sonnetVersion[1]) >= 5 ? 65536 : 16384;
54
53
  if (id.includes('sonnet')) return 16384;
55
- if (id.includes('haiku')) return 8192;
56
- return 8192;
54
+ return MAX_TOKENS_FLOOR;
55
+ }
56
+
57
+ function sharedCatalogOutputTokens(model) {
58
+ const declared = Number(getModelMetadataSync(String(model || ''), 'anthropic')?.outputTokens);
59
+ return Number.isFinite(declared) && declared > 0 ? declared : null;
57
60
  }
58
61
 
59
62
  // catalogLookup(model) -> number|null. Providers supply their own strategy
60
63
  // for sourcing the catalog array (in-memory mirror + disk fallback for OAuth,
61
64
  // plain disk read for the API-key twin — see anthropic.mjs).
62
- export function resolveAnthropicMaxTokens(model, { catalogLookup } = {}) {
63
- const envOverride = envAnthropicMaxOutputOverride();
64
- if (envOverride != null) return envOverride;
65
- const safetyCap = DEFAULT_SAFETY_CAP;
66
- let catalogValue = null;
67
- if (typeof catalogLookup === 'function') {
68
- try {
69
- catalogValue = catalogLookup(model);
70
- } catch {
71
- catalogValue = null;
65
+ //
66
+ // `modelMaxOutputTokens` (number|null): a gateway-supplied model limit. When
67
+ // positive it takes precedence over every catalog lookup. A declared model
68
+ // maximum is a ceiling: it is never raised to the floor, and the env override
69
+ // is capped by it.
70
+ export function resolveAnthropicMaxTokens(model, { catalogLookup, modelMaxOutputTokens = null } = {}) {
71
+ const isLimit = (value) => Number.isFinite(value) && value > 0;
72
+ let declared = Number(modelMaxOutputTokens);
73
+ if (!isLimit(declared)) {
74
+ declared = null;
75
+ if (typeof catalogLookup === 'function') {
76
+ try {
77
+ declared = catalogLookup(model);
78
+ } catch {
79
+ declared = null;
80
+ }
72
81
  }
82
+ if (!isLimit(declared)) declared = sharedCatalogOutputTokens(model);
73
83
  }
74
- if (Number.isFinite(catalogValue) && catalogValue > 0) {
75
- return Math.max(MAX_TOKENS_FLOOR, Math.min(catalogValue, safetyCap));
76
- }
77
- return Math.min(fallbackAnthropicMaxTokens(model), safetyCap);
84
+ declared = isLimit(declared) ? Math.floor(declared) : null;
85
+ const envOverride = envAnthropicMaxOutputOverride();
86
+ if (envOverride != null) return declared == null ? envOverride : Math.min(envOverride, declared);
87
+ if (declared != null) return Math.min(declared, DEFAULT_SAFETY_CAP);
88
+ return Math.min(fallbackAnthropicMaxTokens(model), DEFAULT_SAFETY_CAP);
78
89
  }
@@ -1,6 +1,6 @@
1
1
  // Anthropic model catalog + message conversion helpers.
2
2
  import { createRequire } from 'node:module';
3
- import { effortValuesForModel } from './anthropic-effort.mjs';
3
+ import { effortValuesForModel, thinkingTypesFromCapabilities } from './anthropic-effort.mjs';
4
4
  import { makeModelCache } from './model-cache.mjs';
5
5
  import { resolveAnthropicMaxTokens } from './anthropic-max-tokens.mjs';
6
6
  import {
@@ -73,6 +73,7 @@ export function _normalizeAnthropicModel(raw, provider = 'anthropic') {
73
73
  const dated = /-\d{8}$/.test(String(id));
74
74
  const versioned = !dated && /^claude-[a-z]+-\d+(?:-\d+)?$/i.test(String(id));
75
75
  const effortValues = effortValuesForModel(raw?.capabilities, id);
76
+ const thinkingTypes = thinkingTypesFromCapabilities(raw?.capabilities);
76
77
  return {
77
78
  id,
78
79
  display: raw?.display_name || raw?.displayName || raw?.display || _prettyName(id, family),
@@ -90,6 +91,7 @@ export function _normalizeAnthropicModel(raw, provider = 'anthropic') {
90
91
  latest: false,
91
92
  supportsReasoning: effortValues.length > 0 || _capabilitySupported(raw?.capabilities?.thinking),
92
93
  reasoningOptions: effortValues.length ? [{ type: 'effort', values: effortValues }] : [],
94
+ ...(thinkingTypes ? { thinkingTypes } : {}),
93
95
  };
94
96
  }
95
97
  // The API-key provider has no catalog cache of its own — it reads the same
@@ -129,8 +131,8 @@ function _catalogOutputTokensFromSharedCache(model) {
129
131
  }
130
132
  }
131
133
 
132
- export function resolveMaxTokens(model) {
133
- return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokensFromSharedCache });
134
+ export function resolveMaxTokens(model, { modelMaxOutputTokens = null } = {}) {
135
+ return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokensFromSharedCache, modelMaxOutputTokens });
134
136
  }
135
137
 
136
138
  // Test-only escape hatch for the provider contract scripts
@@ -142,11 +144,12 @@ export const _test = {
142
144
  sanitizeInputSchema: (schema, toolName) => sanitizeAnthropicInputSchema(schema, toolName, 'anthropic'),
143
145
  };
144
146
 
145
- function deferredAnthropicTools(activeTools, messages, opts) {
146
- return sharedDeferredAnthropicTools(activeTools, messages, opts, 'anthropic');
147
+ function deferredAnthropicTools(activeTools, messages, opts, provider = 'anthropic') {
148
+ return sharedDeferredAnthropicTools(activeTools, messages, opts, provider);
147
149
  }
148
- export function requestAnthropicTools(tools, messages, opts) {
149
- return sharedRequestAnthropicTools(tools, messages, opts, 'anthropic');
150
+ // `provider`: the engine's name (a gateway Messages engine runs under its gateway's).
151
+ export function requestAnthropicTools(tools, messages, opts, provider = 'anthropic') {
152
+ return sharedRequestAnthropicTools(tools, messages, opts, provider);
150
153
  }
151
154
  // Test-only: expose the lowering so the steering-provenance test can assert
152
155
  // the API-key provider keeps steering-tagged user turns distinct (mirrors