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,15 +14,36 @@ import {
14
14
  toOpenAITools,
15
15
  parseToolCalls,
16
16
  knownToolNamesFromOpenAITools,
17
- deepseekReplaysReasoningContent,
18
17
  } from './openai-compat-wire.mjs';
19
- import { applyCompatProviderChatOptions } from './openai-compat-options.mjs';
18
+ import { applyCompatProviderChatOptions, deepseekThinkingMode } from './openai-compat-options.mjs';
20
19
  import { normalizeCompatChatResponse } from './openai-compat-response-normalization.mjs';
21
20
  import { applyCompatToolChoice, compatStreamRetryReporter } from './compat-request-policy.mjs';
22
21
  import { ensureChatToolPairs } from './lib/wire-pairing.mjs';
23
22
  import { xaiCacheRouting } from './openai-compat-xai.mjs';
23
+ import { compatRetryOptions, withCompatRetryProfile } from './openai-compat-retry-profile.mjs';
24
24
  import { preparePdfTextForProvider } from './media-normalization.mjs';
25
- import { isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
25
+ import { customWireFormat, isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
26
+ import { geminiAcceptedTools } from './gemini-schema.mjs';
27
+ import { acceptedWireTools } from './lib/claude-bridge-schema.mjs';
28
+ import { isGeminiFamilyModel } from './gemini-family.mjs';
29
+ import { compatReasoningShape, isTogetherBaseURL, readChatMessage } from './openai-compat-reasoning-field.mjs';
30
+
31
+ // Endpoint families with their own reasoning field (Together, vLLM, Groq,
32
+ // Mistral, OpenRouter); a custom provider's row may declare the vLLM format.
33
+ function reasoningShapeFor(provider, modelInfo) {
34
+ return compatReasoningShape({
35
+ providerName: provider.name,
36
+ baseURL: provider.baseURL,
37
+ wireFormat: isCustomProviderName(provider.name) ? customWireFormat(modelInfo, provider.baseURL) : undefined,
38
+ });
39
+ }
40
+
41
+ // The `developer` role is documented by MiMo and by Together's gpt-oss models;
42
+ // every other chat endpoint only knows `system`.
43
+ function keepsDeveloperRole(provider, profile, useModel) {
44
+ if (profile?.developerRole === true) return true;
45
+ return isTogetherBaseURL(provider.baseURL) && /gpt-oss/i.test(String(useModel || ''));
46
+ }
26
47
 
27
48
  export async function sendCompatChat(provider, messages, useModel, tools, opts) {
28
49
  const signal = opts.signal || null;
@@ -48,13 +69,17 @@ export async function sendCompatChat(provider, messages, useModel, tools, opts)
48
69
  protocol: 'openai-chat',
49
70
  model: modelInfo,
50
71
  effort: opts.effort ?? provider.config?.reasoningEffort,
72
+ baseURL: provider.baseURL,
51
73
  })
52
74
  : null;
75
+ // DeepSeek thinking models need the prior reasoning_content back once tools
76
+ // are in play and ignore it otherwise, so it always goes back.
53
77
  const replaysReasoningContent = isCustom
54
78
  ? customReasoning.replay
55
79
  : modelInfo?.reasoningContentField === 'reasoning_content' ||
56
80
  profile?.replaysReasoningContent === true ||
57
- (provider.name === 'deepseek' && deepseekReplaysReasoningContent(useModel));
81
+ provider.name === 'deepseek';
82
+ const reasoningShape = reasoningShapeFor(provider, modelInfo);
58
83
  messages = await preparePdfTextForProvider(messages, provider);
59
84
  const params = {
60
85
  model: useModel,
@@ -64,93 +89,125 @@ export async function sendCompatChat(provider, messages, useModel, tools, opts)
64
89
  messages: ensureChatToolPairs(
65
90
  toOpenAIMessages(messages, provider.name, {
66
91
  replaysReasoningContent,
92
+ ...(reasoningShape ? { reasoningShape } : {}),
67
93
  ...(isCustom ? { customReplay: customReasoning.replay } : {}),
94
+ ...(keepsDeveloperRole(provider, profile, useModel) ? { developerRole: true } : {}),
68
95
  nativePdf: provider.nativePdf,
96
+ cacheControl: provider.chatCacheControl === true,
69
97
  })
70
98
  ),
71
99
  };
72
100
  const maxOutputTokens = resolveCompatMaxOutputTokens(opts);
73
101
  if (maxOutputTokens) params.max_tokens = maxOutputTokens;
74
- if (tools?.length) params.tools = toOpenAITools(tools);
75
- applyCompatToolChoice(params, opts);
102
+ // A Gemini-family model behind this route (google/gemini-* on OpenRouter)
103
+ // fails the whole request on one schema Google rejects; such a tool is left
104
+ // out and reported like on the native Gemini routes.
105
+ // Every other model's `parameters` must be a valid 2020-12 object schema;
106
+ // a draft-07 one is lowered and a broken one left out and reported.
107
+ let sendTools = tools;
108
+ if (tools?.length) {
109
+ sendTools = isGeminiFamilyModel(useModel)
110
+ ? geminiAcceptedTools(tools, opts.onToolExcluded)
111
+ : acceptedWireTools(tools, 'openai', opts.onToolExcluded, `[${provider.name}] tool`);
112
+ }
113
+ if (sendTools?.length) params.tools = toOpenAITools(sendTools);
114
+ // A forced tool_choice goes out only on the documented providers; DeepSeek
115
+ // gets it only with thinking explicitly disabled (never silently in thinking
116
+ // mode, and never as an error for a turn whose thinking is enabled).
117
+ applyCompatToolChoice(params, opts, {
118
+ provider: provider.name,
119
+ baseURL: provider.baseURL,
120
+ wire: 'chat',
121
+ thinking:
122
+ provider.name === 'deepseek' && deepseekThinkingMode(opts, provider.config) === 'disabled' ? 'disabled' : null,
123
+ });
76
124
  applyCompatProviderChatOptions(params, provider.name, opts, provider.config, modelInfo);
77
125
  profile?.applyParams?.(params, { opts, config: provider.config, modelInfo });
78
126
  const firstByteTimeoutMs = profile?.firstByteTimeoutMs || PROVIDER_FIRST_BYTE_TIMEOUT_MS;
79
127
  const totalSignal = createPassthroughSignal(signal);
80
128
  const cacheRouting = provider.name === 'xai' ? xaiCacheRouting(opts, params, tools || [], useModel) : null;
81
129
  const cacheRoutingKey = cacheRouting?.key || null;
130
+ // xAI Chat pins a conversation to the server holding its cached prefix with
131
+ // the x-grok-conv-id header (the Responses equivalent is prompt_cache_key).
132
+ const requestHeaders = cacheRoutingKey
133
+ ? { 'x-grok-conv-id': cacheRoutingKey, ...(opts.requestHeaders || {}) }
134
+ : opts.requestHeaders;
82
135
  params.stream = true;
83
136
  params.stream_options = { include_usage: true };
84
137
  let assembled;
85
138
  try {
86
139
  try {
87
140
  assembled = await withRetry(
88
- refineAttemptErrors(profile, async ({ signal: attemptSignal }) => {
89
- try {
90
- opts.onStageChange?.('requesting');
91
- } catch {
92
- /* heartbeat best-effort */
93
- }
94
- const stream = await withRetry(
95
- ({ signal: openSignal }) =>
96
- provider.client.chat.completions.create(params, {
97
- signal: openSignal,
98
- ...(opts.requestHeaders ? { headers: opts.requestHeaders } : {}),
99
- }),
100
- {
101
- signal: attemptSignal,
102
- // Single attempt: this inner wrapper exists only to
103
- // apply the first-byte per-attempt timeout. Retry is
104
- // owned by the outer withRetry — nesting retry loops
105
- // here multiplied tail latency (5x5).
106
- maxAttempts: 1,
107
- perAttemptTimeoutMs: firstByteTimeoutMs,
108
- perAttemptLabel: `${provider.name} first byte`,
141
+ withCompatRetryProfile(
142
+ provider.name,
143
+ refineAttemptErrors(profile, async ({ signal: attemptSignal }) => {
144
+ try {
145
+ opts.onStageChange?.('requesting');
146
+ } catch {
147
+ /* heartbeat best-effort */
148
+ }
149
+ const stream = await withRetry(
150
+ ({ signal: openSignal }) =>
151
+ provider.client.chat.completions.create(params, {
152
+ signal: openSignal,
153
+ ...(requestHeaders ? { headers: requestHeaders } : {}),
154
+ }),
155
+ {
156
+ signal: attemptSignal,
157
+ // Single attempt: this inner wrapper exists only to
158
+ // apply the first-byte per-attempt timeout. Retry is
159
+ // owned by the outer withRetry — nesting retry loops
160
+ // here multiplied tail latency (5x5).
161
+ maxAttempts: 1,
162
+ perAttemptTimeoutMs: firstByteTimeoutMs,
163
+ perAttemptLabel: `${provider.name} first byte`,
164
+ }
165
+ );
166
+ try {
167
+ opts.onStageChange?.('streaming');
168
+ } catch {
169
+ /* heartbeat best-effort */
109
170
  }
110
- );
111
- try {
112
- opts.onStageChange?.('streaming');
113
- } catch {
114
- /* heartbeat best-effort */
115
- }
116
- try {
117
- return await consumeCompatChatCompletionStream(stream, {
118
- signal: attemptSignal,
119
- label: provider.name,
120
- providerName: provider.name,
121
- onStreamDelta: opts.onStreamDelta,
122
- onToolCall: opts.onToolCall,
123
- onTextDelta: opts.onTextDelta,
124
- parseToolCalls,
125
- // Known tool names for the leaked-tool-call guard:
126
- // recovered leaked calls only synthesize when they name
127
- // a tool actually offered to this request.
128
- knownToolNames: knownToolNamesFromOpenAITools(params.tools),
129
- ...(profile?.firstByteTimeoutMs ? { firstByteTimeoutMs: profile.firstByteTimeoutMs } : {}),
130
- ...(profile?.semanticIdleTimeoutMs ? { semanticIdleTimeoutMs: profile.semanticIdleTimeoutMs } : {}),
131
- });
132
- } catch (error) {
133
- // Grok's reference sampler treats content-idle as a
134
- // terminal sampling decision, not a resample signal.
135
- if (provider.name === 'xai' && error?.streamStalled === true) {
136
- throw markProviderRecoveryExhausted(error, {
137
- owner: 'xai-content-idle-policy',
171
+ try {
172
+ return await consumeCompatChatCompletionStream(stream, {
173
+ signal: attemptSignal,
174
+ label: provider.name,
175
+ providerName: provider.name,
176
+ onStreamDelta: opts.onStreamDelta,
177
+ onToolCall: opts.onToolCall,
178
+ onTextDelta: opts.onTextDelta,
179
+ parseToolCalls,
180
+ // Known tool names for the leaked-tool-call guard:
181
+ // recovered leaked calls only synthesize when they name
182
+ // a tool actually offered to this request.
183
+ knownToolNames: knownToolNamesFromOpenAITools(params.tools),
184
+ ...(profile?.firstByteTimeoutMs ? { firstByteTimeoutMs: profile.firstByteTimeoutMs } : {}),
185
+ ...(profile?.semanticIdleTimeoutMs ? { semanticIdleTimeoutMs: profile.semanticIdleTimeoutMs } : {}),
138
186
  });
187
+ } catch (error) {
188
+ // Grok's reference sampler treats content-idle as a
189
+ // terminal sampling decision, not a resample signal.
190
+ if (provider.name === 'xai' && error?.streamStalled === true) {
191
+ throw markProviderRecoveryExhausted(error, {
192
+ owner: 'xai-content-idle-policy',
193
+ });
194
+ }
195
+ throw error;
139
196
  }
140
- throw error;
141
- }
142
- }),
197
+ })
198
+ ),
143
199
  {
144
200
  signal: totalSignal.signal,
145
201
  onRetry: compatStreamRetryReporter(provider.name, opts),
146
202
  retry529: opts.retry529,
203
+ ...compatRetryOptions(provider.name),
147
204
  }
148
205
  );
149
206
  } catch (streamErr) {
150
207
  const recovered = await provider._recoverCompatNonStreaming({
151
208
  streamErr,
152
209
  params,
153
- opts,
210
+ opts: requestHeaders === opts.requestHeaders ? opts : { ...opts, requestHeaders },
154
211
  signal: totalSignal.signal,
155
212
  useModel,
156
213
  });
@@ -170,6 +227,7 @@ export async function sendCompatChat(provider, messages, useModel, tools, opts)
170
227
  cacheRoutingKey,
171
228
  cacheRouting,
172
229
  replaysReasoningContent,
230
+ reasoningShape,
173
231
  });
174
232
  }
175
233
 
@@ -234,13 +292,17 @@ export async function recoverCompatNonStreaming(provider, { streamErr, params, o
234
292
  /* best-effort */
235
293
  }
236
294
  traceNonStreamingFallback({ provider: provider.name, model: useModel, opts, streamErr });
295
+ const { content, reasoningContent, reasoningSource } = readChatMessage(message, {
296
+ shape: reasoningShapeFor(provider, provider.getCachedModelInfo?.(useModel) || null),
297
+ });
237
298
  return {
238
299
  response,
239
300
  model: response.model || useModel,
240
- content: typeof message.content === 'string' ? message.content : '',
301
+ content,
241
302
  toolCalls,
242
303
  stopReason: choice.finish_reason || null,
243
- reasoningContent: typeof message.reasoning_content === 'string' ? message.reasoning_content : null,
304
+ reasoningContent,
305
+ reasoningSource,
244
306
  rawUsage: response.usage || null,
245
307
  };
246
308
  }
@@ -4,7 +4,18 @@
4
4
  * reasoning aliases, tool_calls deltas, finish reason and usage.
5
5
  */
6
6
  import { mergeToolCallDelta } from './tool-call-acc.mjs';
7
- import { appendText, relayText, reportProgress, reportTransport } from './stream-state.mjs';
7
+ import { appendText, drainLeakedCalls, relayText, reportProgress, reportTransport } from './stream-state.mjs';
8
+ import { chatContentParts } from '../openai-compat-reasoning-field.mjs';
9
+
10
+ function appendReasoning(state, text, source) {
11
+ state.sawReasoningContent = true;
12
+ state.reasoningSource = source;
13
+ state.reasoningContent += text;
14
+ if (text) {
15
+ state.emittedReasoning = true;
16
+ reportProgress(state, 'reasoning');
17
+ }
18
+ }
8
19
 
9
20
  function applyReasoning(state, delta) {
10
21
  if (Array.isArray(delta?.reasoning_details) && delta.reasoning_details.length) {
@@ -12,14 +23,22 @@ function applyReasoning(state, delta) {
12
23
  reportProgress(state, 'reasoning');
13
24
  }
14
25
  // These provider fields are aliases, never independent text segments.
15
- const reasoningDelta =
16
- [delta?.reasoning_content, delta?.reasoning, delta?.thinking].find((value) => typeof value === 'string') ?? null;
17
- if (reasoningDelta === null) return;
18
- state.sawReasoningContent = true;
19
- state.reasoningContent += reasoningDelta;
20
- if (reasoningDelta) {
21
- state.emittedReasoning = true;
22
- reportProgress(state, 'reasoning');
26
+ const source = ['reasoning_content', 'reasoning', 'thinking'].find((key) => typeof delta?.[key] === 'string');
27
+ if (source === undefined) return;
28
+ appendReasoning(state, delta[source], source);
29
+ }
30
+
31
+ function applyContent(state, content) {
32
+ if (state.leakGuard.enabled) relayText(state, content);
33
+ else appendText(state, content);
34
+ }
35
+
36
+ // Mistral-style typed chunk lists: thinking → reasoning, text → assistant
37
+ // text, applied in arrival order.
38
+ function applyContentParts(state, parts) {
39
+ for (const part of parts) {
40
+ if (part.kind === 'reasoning') appendReasoning(state, part.text, 'content_chunks');
41
+ else if (part.text) applyContent(state, part.text);
23
42
  }
24
43
  }
25
44
 
@@ -32,15 +51,17 @@ export function applyCompatChunk(state, chunk) {
32
51
  if (typeof delta?.role === 'string' && delta.role) {
33
52
  reportProgress(state, 'semantic');
34
53
  }
35
- if (delta?.content) {
36
- if (state.leakGuard.enabled) relayText(state, delta.content);
37
- else appendText(state, delta.content);
38
- }
54
+ const contentParts = chatContentParts(delta?.content);
55
+ if (contentParts) applyContentParts(state, contentParts);
56
+ else if (delta?.content) applyContent(state, delta.content);
39
57
  applyReasoning(state, delta);
40
58
  if (Array.isArray(delta?.tool_calls) && delta.tool_calls.length) {
41
59
  reportProgress(state, 'tool');
42
60
  }
43
61
  mergeToolCallDelta(state.toolAcc, delta?.tool_calls);
44
- if (choice?.finish_reason) state.stopReason = choice.finish_reason;
62
+ if (choice?.finish_reason) {
63
+ state.stopReason = choice.finish_reason;
64
+ drainLeakedCalls(state);
65
+ }
45
66
  if (chunk?.usage) state.rawUsage = chunk.usage;
46
67
  }
@@ -8,11 +8,12 @@ import { truncatedCompatStreamError } from '../lib/openai-tool-args.mjs';
8
8
  import {
9
9
  emitCompatToolCallOnce,
10
10
  firstByteCompatStreamError,
11
+ failingFinishReasonError,
11
12
  markErrorLiveTextEmitted,
12
13
  markUnsafeRetryIfToolEmitted,
13
14
  } from '../openai-compat-stream-common.mjs';
14
15
  import { orderedToolCalls, toolCallsFromStreamAcc } from './tool-call-acc.mjs';
15
- import { attachPartial, attachReportedUsage, stampCompatOutcome } from './stream-state.mjs';
16
+ import { attachPartial, attachReportedUsage, isIncompleteFinishReason, stampCompatOutcome } from './stream-state.mjs';
16
17
 
17
18
  /** Rejection for a stream that ended without a terminal event. */
18
19
  export function incompleteStreamError(state, label) {
@@ -61,10 +62,33 @@ function parseAccumulatedToolCalls(state, { label, parseToolCalls }) {
61
62
  }
62
63
  }
63
64
 
65
+ // A gateway-reported failing finish_reason (`network_error`, `error`) is an
66
+ // interruption: the stream carries no terminal, so exposure keeps its replay
67
+ // gates.
68
+ function finishReasonInterruption(state, err) {
69
+ attachPartial(state, err);
70
+ if (state.emittedText) {
71
+ markErrorLiveTextEmitted(err);
72
+ try {
73
+ err.streamStalled = true;
74
+ } catch {
75
+ /* best-effort */
76
+ }
77
+ }
78
+ return stampCompatOutcome(state, markUnsafeRetryIfToolEmitted(err, state.streamEmitState), {
79
+ terminalObserved: false,
80
+ continuation: true,
81
+ });
82
+ }
83
+
64
84
  export function settleCompatStream(state, { label, parseToolCalls }) {
85
+ const failing = failingFinishReasonError(state.stopReason, label);
86
+ if (failing) throw finishReasonInterruption(state, failing);
65
87
  const response = buildResponse(state);
66
88
  let toolCalls = parseAccumulatedToolCalls(state, { label, parseToolCalls });
67
- if (Array.isArray(toolCalls) && toolCalls.length) {
89
+ // A length-truncated or content-filtered call is a partial result that
90
+ // normalizeCompatChatResponse rejects: it must never reach the executor.
91
+ if (!isIncompleteFinishReason(state.stopReason) && Array.isArray(toolCalls) && toolCalls.length) {
68
92
  for (const call of toolCalls) emitCompatToolCallOnce(state.streamEmitState, call, state.onToolCall);
69
93
  }
70
94
  if (state.leakedCalls.length) {
@@ -77,6 +101,7 @@ export function settleCompatStream(state, { label, parseToolCalls }) {
77
101
  toolCalls,
78
102
  stopReason: state.stopReason,
79
103
  reasoningContent: state.sawReasoningContent ? state.reasoningContent : null,
104
+ reasoningSource: state.sawReasoningContent ? state.reasoningSource : null,
80
105
  reasoningDetails: state.reasoningDetails.length ? state.reasoningDetails : null,
81
106
  rawUsage: state.rawUsage,
82
107
  };
@@ -6,7 +6,11 @@
6
6
  */
7
7
  import { stampStreamOutcome, STREAM_TRANSPORTS } from '../lib/stream-outcome.mjs';
8
8
  import { createLeakGuard, createToolCallDedupe } from '../lib/leaked-toolcall.mjs';
9
- import { emitCompatToolCallOnce, synthLeakedOpenAICall } from '../openai-compat-stream-common.mjs';
9
+ import {
10
+ emitCompatToolCallOnce,
11
+ failingFinishReasonError,
12
+ synthLeakedOpenAICall,
13
+ } from '../openai-compat-stream-common.mjs';
10
14
  import { chatCompletionUsage } from '../openai-compat-response-normalization.mjs';
11
15
  import { noteAbandonedUsage } from '../../../../shared/llm/usage-context.mjs';
12
16
  import { createToolCallAccumulator } from './tool-call-acc.mjs';
@@ -31,6 +35,8 @@ export function createCompatStreamState({
31
35
  content: '',
32
36
  reasoningContent: '',
33
37
  sawReasoningContent: false,
38
+ // Where the last reasoning text came from: a delta field name or 'content_chunks'.
39
+ reasoningSource: null,
34
40
  reasoningDetails: [],
35
41
  // Both text and reasoning exposure prohibit resampling the request.
36
42
  emittedText: false,
@@ -43,6 +49,7 @@ export function createCompatStreamState({
43
49
  streamEmitState: { emittedToolCallKeys: new Set(), emittedToolCall: false, _toolDedupe: toolDedupe },
44
50
  leakGuard: createLeakGuard({ knownToolNames, harmony: true }),
45
51
  leakedCalls: [],
52
+ pendingLeakedCalls: [],
46
53
  };
47
54
  }
48
55
 
@@ -71,16 +78,39 @@ export function appendText(state, text) {
71
78
  }
72
79
  }
73
80
 
74
- function dispatchLeakedCall(state, recovered) {
81
+ /** A length-truncated or content-filtered turn is a partial result:
82
+ * normalizeCompatChatResponse rejects it, so no tool call of it may execute. */
83
+ export function isIncompleteFinishReason(finishReason) {
84
+ return finishReason === 'length' || finishReason === 'content_filter';
85
+ }
86
+
87
+ /** Whether `finish_reason` confirms a normal end of the turn: present, not an
88
+ * incomplete outcome and not a gateway-reported failure (network_error/error). */
89
+ export function isNormalFinishReason(finishReason) {
90
+ return Boolean(finishReason) && !isIncompleteFinishReason(finishReason) && !failingFinishReasonError(finishReason, '');
91
+ }
92
+
93
+ /** Dispatch held leaked calls once a normal finish_reason confirms the turn
94
+ * ended. Otherwise they stay on `leakedCalls` (partial tool calls) and never
95
+ * reach the executor. */
96
+ export function drainLeakedCalls(state) {
97
+ if (!isNormalFinishReason(state.stopReason)) return;
98
+ for (const call of state.pendingLeakedCalls.splice(0)) {
99
+ emitCompatToolCallOnce(state.streamEmitState, call, state.onToolCall);
100
+ }
101
+ }
102
+
103
+ function recordLeakedCall(state, recovered) {
75
104
  const call = synthLeakedOpenAICall(recovered);
76
- emitCompatToolCallOnce(state.streamEmitState, call, state.onToolCall);
105
+ state.pendingLeakedCalls.push(call);
77
106
  reportProgress(state, 'tool');
78
107
  return call;
79
108
  }
80
109
 
81
110
  function relayGuarded(state, { text, calls }) {
82
111
  if (text) appendText(state, text);
83
- for (const c of calls) state.leakedCalls.push(dispatchLeakedCall(state, c));
112
+ for (const c of calls) state.leakedCalls.push(recordLeakedCall(state, c));
113
+ drainLeakedCalls(state);
84
114
  }
85
115
 
86
116
  /** Route a text delta through the leak guard, dispatching rescued calls. */
@@ -113,9 +143,9 @@ export function noteReportedUsage(state) {
113
143
  }
114
144
 
115
145
  /** Keep the partial output on the error for upstream salvage: the text, the
116
- * recovered leaked calls already dispatched (native calls only dispatch once
117
- * the stream finishes) and whether a native call's arguments were still
118
- * streaming. */
146
+ * recovered leaked calls (none dispatched unless a normal finish_reason
147
+ * arrived; native calls only dispatch once the stream finishes) and whether a
148
+ * native call's arguments were still streaming. */
119
149
  export function attachPartial(state, err) {
120
150
  try {
121
151
  err.partialContent = state.content;
@@ -35,15 +35,8 @@ export function mergeToolCallDelta(acc, deltaCalls) {
35
35
  if (tc.id) prev.id = tc.id;
36
36
  if (tc.type) prev.type = tc.type;
37
37
  if (tc.function?.name && !prev.function.name) prev.function.name = tc.function.name;
38
- if (tc.function?.arguments) {
39
- const delta = tc.function.arguments;
40
- // Preserve support for providers that repeat cumulative arguments.
41
- if (prev.function.arguments && delta.startsWith(prev.function.arguments)) {
42
- prev.function.arguments = delta;
43
- } else {
44
- prev.function.arguments += delta;
45
- }
46
- }
38
+ // Argument fragments are deltas: always append, never infer snapshots.
39
+ if (tc.function?.arguments) prev.function.arguments += tc.function.arguments;
47
40
  }
48
41
  }
49
42
 
@@ -71,6 +71,7 @@ export async function consumeCompatChatCompletionStream(
71
71
  idleDeadlineAt: state.semanticIdleDeadlineAt,
72
72
  idleEnabled: state.sawFirstEvent && idleEnabled && state.semanticIdleDeadlineAt > 0,
73
73
  idleLabel: `${label} SSE idle`,
74
+ streamLabel: label,
74
75
  emittedToolCall: () => toolWorkStarted(state),
75
76
  });
76
77
  if (done) {
@@ -0,0 +1,50 @@
1
+ /**
2
+ * openai-compat-error-contract.mjs — the error contract of the OpenAI-compatible
3
+ * provider boundary: `status`, lowercased `code` (from the wire error's `code`
4
+ * or `type`), `headers`, `retryAfterMs` and `resetAt` when the provider sent
5
+ * them. Evidence is structural only; message text is never parsed.
6
+ */
7
+ import { retryAfterMsFromError, typedStatusFrom } from './retry-classifier.mjs';
8
+
9
+ const lowered = (value) => (typeof value === 'string' && value.trim() ? value.trim().toLowerCase() : '');
10
+
11
+ // Epoch seconds, epoch ms or an ISO date → epoch ms; `resets_in_seconds` is relative.
12
+ function resetAtFrom(wire, now) {
13
+ const inSeconds = Number(wire?.resets_in_seconds);
14
+ if (wire?.resets_in_seconds != null && Number.isFinite(inSeconds) && inSeconds >= 0) {
15
+ return now + Math.ceil(inSeconds * 1000);
16
+ }
17
+ const raw = wire?.resets_at ?? wire?.reset_at ?? wire?.metadata?.resets_at;
18
+ if (raw == null || raw === '') return null;
19
+ const numeric = Number(raw);
20
+ if (Number.isFinite(numeric) && numeric > 0) return numeric < 1e12 ? Math.round(numeric * 1000) : Math.round(numeric);
21
+ const parsed = Date.parse(String(raw));
22
+ return Number.isNaN(parsed) ? null : parsed;
23
+ }
24
+
25
+ /** Stamp the boundary contract onto a provider error in place and return it. */
26
+ export function applyCompatErrorContract(err, detail = err?.error ?? err?.providerError, now = Date.now()) {
27
+ if (!err || typeof err !== 'object') return err;
28
+ try {
29
+ const wire = detail && typeof detail === 'object' ? detail : null;
30
+ const status = typedStatusFrom(err, err.response, wire);
31
+ if (status && !(Number(err.status) >= 100)) err.status = status;
32
+ const wireCode = lowered(wire?.code) || lowered(wire?.type) || lowered(err.type);
33
+ // Keep an errno / SDK-local code (ECONNRESET, ...) that is not the wire code.
34
+ if (wireCode && (typeof err.code !== 'string' || !err.code.trim() || lowered(err.code) === wireCode)) {
35
+ err.code = wireCode;
36
+ }
37
+ if (!err.headers && err.response?.headers) err.headers = err.response.headers;
38
+ if (!Number.isFinite(err.retryAfterMs)) {
39
+ const retryAfterMs = retryAfterMsFromError(err);
40
+ if (retryAfterMs != null) err.retryAfterMs = retryAfterMs;
41
+ }
42
+ if (!Number.isFinite(err.resetAt)) {
43
+ const resetAt = resetAtFrom(wire, now);
44
+ if (resetAt) err.resetAt = resetAt;
45
+ }
46
+ } catch {
47
+ /* the contract is best-effort; the original error stays authoritative */
48
+ }
49
+ return err;
50
+ }
@@ -34,6 +34,25 @@ export async function fetchCompatModelItems(provider, { signal = null, keyless =
34
34
  }
35
35
  }
36
36
 
37
+ // Provider-native chat-ness: Together `type`, Mistral `capabilities`. Returns a
38
+ // sanitize-compatible mode, or null when the listing says nothing.
39
+ function nativeMode(m) {
40
+ const type = typeof m?.type === 'string' ? m.type.trim().toLowerCase() : '';
41
+ if (type === 'chat') return 'chat';
42
+ if (type === 'language' || type === 'code') return 'completion';
43
+ if (['embedding', 'embeddings', 'image', 'audio', 'rerank', 'moderation', 'video', 'transcribe'].includes(type)) {
44
+ return type;
45
+ }
46
+ // OpenRouter: a model that cannot emit text (image/audio generation) is no chat model.
47
+ const outputs = m?.architecture?.output_modalities;
48
+ if (Array.isArray(outputs) && outputs.length && !outputs.includes('text')) return 'non_chat';
49
+ const caps = m?.capabilities;
50
+ if (caps && typeof caps === 'object' && typeof caps.completion_chat === 'boolean') {
51
+ return caps.completion_chat ? 'chat' : 'non_chat';
52
+ }
53
+ return null;
54
+ }
55
+
37
56
  export async function listCompatModels(provider, { throwOnError = false, signal = null } = {}) {
38
57
  try {
39
58
  const list = await provider._fetchModelItems({ signal });
@@ -45,10 +64,23 @@ export async function listCompatModels(provider, { throwOnError = false, signal
45
64
  m?.max_input_tokens ??
46
65
  m?.max_model_len ??
47
66
  m?.context_length ??
67
+ m?.max_context_length ??
68
+ m?.top_provider?.context_length ??
48
69
  m?.contextWindow ??
49
70
  0
50
71
  );
51
- const outputTokens = Number(m?.max_output_tokens ?? m?.output_tokens ?? m?.maxOutputTokens ?? 0);
72
+ const outputTokens = Number(
73
+ m?.max_output_tokens ??
74
+ m?.output_tokens ??
75
+ m?.maxOutputTokens ??
76
+ m?.top_provider?.max_completion_tokens ??
77
+ 0
78
+ );
79
+ const mode = nativeMode(m);
80
+ // A catalog alias (OpenRouter `~anthropic/claude-opus-latest`) keeps its
81
+ // own slug for routing; the slug it currently points at is retained for
82
+ // capability lookup only.
83
+ const aliasTarget = typeof m?.alias_target === 'string' ? m.alias_target : m?.alias_target?.slug;
52
84
  models.push({
53
85
  id: m?.id,
54
86
  name: m?.id,
@@ -56,10 +88,23 @@ export async function listCompatModels(provider, { throwOnError = false, signal
56
88
  contextWindow: Number.isFinite(contextWindow) && contextWindow > 0 ? contextWindow : 0,
57
89
  outputTokens: Number.isFinite(outputTokens) && outputTokens > 0 ? outputTokens : null,
58
90
  created: typeof m?.created === 'number' ? m.created : null,
91
+ ...(mode ? { mode } : {}),
92
+ ...(typeof aliasTarget === 'string' && aliasTarget ? { aliasTarget } : {}),
59
93
  });
60
94
  }
61
95
  const filtered = models.filter((m) => m.id);
62
- const enriched = sanitizeModelList(await enrichModels(filtered), { provider: provider.name });
96
+ // The catalog fills gaps only: native limits and chat-ness are restored
97
+ // over whatever enrichment derived.
98
+ const enrichedRows = (await enrichModels(filtered)).map((row, i) => {
99
+ const native = filtered[i];
100
+ return {
101
+ ...row,
102
+ ...(native.contextWindow ? { contextWindow: native.contextWindow } : {}),
103
+ ...(native.outputTokens ? { outputTokens: native.outputTokens } : {}),
104
+ ...(native.mode ? { mode: native.mode } : {}),
105
+ };
106
+ });
107
+ const enriched = sanitizeModelList(enrichedRows, { provider: provider.name });
63
108
  provider._enrichedModels = enriched;
64
109
  return enriched;
65
110
  } catch (error) {