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
@@ -12,6 +12,41 @@ function normalizeReasoningEffort(value, allowed) {
12
12
  return allowed.includes(effort) ? effort : null;
13
13
  }
14
14
 
15
+ /**
16
+ * OpenRouter's unified `reasoning` field, shared by its Chat and Responses
17
+ * wires: `openRouterReasoningEffort`, else the turn effort, else the configured
18
+ * effort; `none` disables reasoning. Null when no effort applies.
19
+ */
20
+ export function openRouterReasoning(opts = {}, config = {}) {
21
+ const effort = normalizeReasoningEffort(opts.openRouterReasoningEffort ?? opts.effort ?? config?.reasoningEffort, [
22
+ 'none',
23
+ 'minimal',
24
+ 'low',
25
+ 'medium',
26
+ 'high',
27
+ 'xhigh',
28
+ 'max',
29
+ ]);
30
+ if (effort === 'none') return { enabled: false };
31
+ return effort ? { enabled: true, effort } : null;
32
+ }
33
+
34
+ function deepseekRawEffort(opts, config) {
35
+ return opts.deepseekReasoningEffort ?? opts.effort ?? config?.reasoningEffort;
36
+ }
37
+
38
+ /** 'enabled' | 'disabled' as the DeepSeek request will carry it, or null when nothing sets it. */
39
+ export function deepseekThinkingMode(opts = {}, config = {}) {
40
+ const rawThinking = opts.deepseekThinking ?? opts.thinking ?? config?.thinking;
41
+ const rawEffort = deepseekRawEffort(opts, config);
42
+ if (rawThinking === undefined && rawEffort === undefined) return null;
43
+ const thinkingMode = String(rawThinking?.type ?? rawThinking ?? rawEffort)
44
+ .trim()
45
+ .toLowerCase();
46
+ const disabled = rawThinking === false || thinkingMode === 'disabled' || thinkingMode === 'none';
47
+ return disabled ? 'disabled' : 'enabled';
48
+ }
49
+
15
50
  // Keep provider extensions isolated: fields accepted by one OpenAI-compatible
16
51
  // backend are frequently rejected by another even when the core Chat schema
17
52
  // is shared.
@@ -23,22 +58,14 @@ export function applyCompatProviderChatOptions(params, providerName, opts = {},
23
58
  protocol: 'openai-chat',
24
59
  model: modelInfo,
25
60
  effort: opts.effort ?? config?.reasoningEffort,
61
+ baseURL: config?.baseURL,
26
62
  });
27
63
  Object.assign(params, fields);
28
64
  return params;
29
65
  }
30
66
  if (providerName === 'openrouter') {
31
- const effort = normalizeReasoningEffort(opts.openRouterReasoningEffort ?? opts.effort ?? config?.reasoningEffort, [
32
- 'none',
33
- 'minimal',
34
- 'low',
35
- 'medium',
36
- 'high',
37
- 'xhigh',
38
- 'max',
39
- ]);
40
- if (effort === 'none') params.reasoning = { enabled: false };
41
- else if (effort) params.reasoning = { enabled: true, effort };
67
+ const reasoning = openRouterReasoning(opts, config);
68
+ if (reasoning) params.reasoning = reasoning;
42
69
  return params;
43
70
  }
44
71
  if (providerName === 'xai') {
@@ -53,22 +80,17 @@ export function applyCompatProviderChatOptions(params, providerName, opts = {},
53
80
  return params;
54
81
  }
55
82
  if (providerName === 'deepseek') {
56
- const rawThinking = opts.deepseekThinking ?? opts.thinking ?? config?.thinking;
57
- const rawEffort = opts.deepseekReasoningEffort ?? opts.effort ?? config?.reasoningEffort;
58
- if (rawThinking !== undefined || rawEffort !== undefined) {
59
- const thinkingMode = String(rawThinking?.type ?? rawThinking ?? rawEffort)
60
- .trim()
61
- .toLowerCase();
62
- const disabled = rawThinking === false || thinkingMode === 'disabled' || thinkingMode === 'none';
63
- params.thinking = { type: disabled ? 'disabled' : 'enabled' };
64
- if (!disabled) {
65
- const effort = String(rawEffort ?? '')
83
+ const mode = deepseekThinkingMode(opts, config);
84
+ if (mode) {
85
+ params.thinking = { type: mode };
86
+ if (mode === 'enabled') {
87
+ const effort = String(deepseekRawEffort(opts, config) ?? '')
66
88
  .trim()
67
89
  .toLowerCase();
68
- if (effort === 'max') params.reasoning_effort = 'max';
69
- // DeepSeek documents low/high/max; `medium` is its own alias for
70
- // high, and `low` is a real level that must not be promoted.
71
- else if (effort === 'low') params.reasoning_effort = 'low';
90
+ // DeepSeek documents low/high/max; `ultra` is its alias for max,
91
+ // `minimal` for low, `medium`/`xhigh` for high; `low` must not be promoted.
92
+ if (effort === 'max' || effort === 'ultra') params.reasoning_effort = 'max';
93
+ else if (effort === 'low' || effort === 'minimal') params.reasoning_effort = 'low';
72
94
  else if (['medium', 'high', 'xhigh'].includes(effort)) params.reasoning_effort = 'high';
73
95
  }
74
96
  }
@@ -11,12 +11,16 @@ export const OPENAI_COMPAT_PRESETS = {
11
11
  },
12
12
  // OpenCode Go - low-cost coding-model subscription gateway.
13
13
  'opencode-go': {
14
- baseURL: 'https://opencode.ai/zen/go/v1',
14
+ baseURL: 'https://opencode.ai/inference/go/v1',
15
15
  defaultModel: 'glm-5.2',
16
+ // The gateway expects an application User-Agent (not the SDK default).
17
+ extraHeaders: { 'User-Agent': 'mixdog' },
16
18
  },
17
19
  openrouter: {
18
20
  baseURL: 'https://openrouter.ai/api/v1',
19
21
  defaultModel: 'openrouter/auto',
22
+ // OpenRouter documents cache_control on Chat content blocks.
23
+ chatCacheControl: true,
20
24
  extraHeaders: {
21
25
  'HTTP-Referer': 'https://github.com/tribgames/mixdog',
22
26
  'X-OpenRouter-Title': 'mixdog',
@@ -0,0 +1,151 @@
1
+ /**
2
+ * openai-compat-reasoning-field.mjs — provider-specific reasoning shapes on the
3
+ * Chat Completions wire that the plain `reasoning_content` string path misses.
4
+ *
5
+ * Together AI (docs.together.ai/docs/inference/chat/reasoning): the chain of
6
+ * thought arrives on `reasoning` OR `reasoning_content` (model dependent), on
7
+ * the message and on each streaming delta, and must be passed back "under the
8
+ * same key" on prior assistant turns. vLLM reports it on `reasoning` (formerly
9
+ * `reasoning_content`), Groq on `message.reasoning` (reasoning_format parsed).
10
+ * OpenRouter reports plain text on `reasoning` next to `reasoning_details`.
11
+ *
12
+ * Mistral (docs.mistral.ai/studio/conversations/reasoning): with reasoning on,
13
+ * `message.content` / `delta.content` is a list of typed chunks —
14
+ * `{type:'thinking', thinking:[{type:'text', text}]}` and `{type:'text', text}`
15
+ * — and the full assistant message, thinking chunk included, goes back in the
16
+ * history. Receiving is by the response shape (an array), never by model name.
17
+ */
18
+
19
+ /** `message.providerMetadata[key].reasoningField`: the key a reply's reasoning arrived on. */
20
+ export const COMPAT_REASONING_METADATA_KEY = 'openaiCompat';
21
+
22
+ const TOGETHER_HOSTS = ['together.xyz', 'together.ai'];
23
+ const GROQ_HOSTS = ['groq.com'];
24
+ const MISTRAL_HOSTS = ['mistral.ai'];
25
+
26
+ function hostMatches(baseURL, domains) {
27
+ let host;
28
+ try {
29
+ host = new URL(String(baseURL || '')).hostname.toLowerCase();
30
+ } catch {
31
+ return false;
32
+ }
33
+ return domains.some((domain) => host === domain || host.endsWith(`.${domain}`));
34
+ }
35
+
36
+ export function isTogetherBaseURL(baseURL) {
37
+ return hostMatches(baseURL, TOGETHER_HOSTS);
38
+ }
39
+
40
+ /**
41
+ * Where an endpoint family reports reasoning and how a prior turn's reasoning
42
+ * goes back. `readsReasoningAlias`: the `reasoning` key is a reasoning field
43
+ * (otherwise only `reasoning_content` is). `resend`:
44
+ * same_key — back under the key it arrived on (Together, vLLM)
45
+ * reasoning — plain text as `reasoning`; reasoning_details win (OpenRouter)
46
+ * content_chunks — as a `thinking` chunk in the assistant content (Mistral)
47
+ * none — never echoed; the docs do not ask for it (Groq)
48
+ */
49
+ const SHAPES = Object.freeze({
50
+ together: Object.freeze({ id: 'together', readsReasoningAlias: true, resend: 'same_key' }),
51
+ vllm: Object.freeze({ id: 'vllm', readsReasoningAlias: true, resend: 'same_key' }),
52
+ groq: Object.freeze({ id: 'groq', readsReasoningAlias: true, resend: 'none' }),
53
+ mistral: Object.freeze({ id: 'mistral', readsReasoningAlias: false, resend: 'content_chunks' }),
54
+ openrouter: Object.freeze({ id: 'openrouter', readsReasoningAlias: true, resend: 'reasoning' }),
55
+ });
56
+
57
+ /**
58
+ * The reasoning shape of a provider, or null for the plain `reasoning_content`
59
+ * path. OpenRouter is by provider name, Together/Groq/Mistral by the provider's
60
+ * own base URL, vLLM (no fixed host) by the model row's `vllm` wire format.
61
+ */
62
+ export function compatReasoningShape({ providerName, baseURL, wireFormat } = {}) {
63
+ if (providerName === 'openrouter') return SHAPES.openrouter;
64
+ if (wireFormat === 'together' || isTogetherBaseURL(baseURL)) return SHAPES.together;
65
+ if (wireFormat === 'vllm') return SHAPES.vllm;
66
+ if (hostMatches(baseURL, GROQ_HOSTS)) return SHAPES.groq;
67
+ if (hostMatches(baseURL, MISTRAL_HOSTS)) return SHAPES.mistral;
68
+ return null;
69
+ }
70
+
71
+ /**
72
+ * The receive field worth recording for replay: `reasoning` (non-default key)
73
+ * or `content_chunks` (Mistral), per shape; `reasoning_content` is the default
74
+ * and needs no record. Null when nothing needs remembering.
75
+ */
76
+ export function replayReasoningField(shape, source) {
77
+ if (!shape) return null;
78
+ if (shape.resend === 'same_key' && source === 'reasoning') return 'reasoning';
79
+ if (shape.resend === 'content_chunks' && source === 'content_chunks') return 'content_chunks';
80
+ return null;
81
+ }
82
+
83
+ /** Whether a reply's reasoning source is captured under this shape. */
84
+ export function capturesShapeReasoning(shape, source) {
85
+ if (!shape) return source === 'content_chunks';
86
+ if (source === 'content_chunks') return true;
87
+ return source === 'reasoning_content' || (shape.readsReasoningAlias && source === 'reasoning');
88
+ }
89
+
90
+ /** Assistant content with the prior reasoning replayed as a leading `thinking` chunk. */
91
+ export function contentWithThinkingChunk(content, reasoning) {
92
+ const thinking = { type: 'thinking', thinking: [{ type: 'text', text: reasoning }] };
93
+ if (Array.isArray(content)) return [thinking, ...content];
94
+ return typeof content === 'string' && content ? [thinking, { type: 'text', text: content }] : [thinking];
95
+ }
96
+
97
+ function thinkingText(thinking) {
98
+ if (typeof thinking === 'string') return thinking;
99
+ if (!Array.isArray(thinking)) return '';
100
+ return thinking
101
+ .map((inner) => (typeof inner === 'string' ? inner : typeof inner?.text === 'string' ? inner.text : ''))
102
+ .join('');
103
+ }
104
+
105
+ /**
106
+ * Ordered `{kind:'reasoning'|'text', text}` parts of an array-shaped `content`,
107
+ * or null when `content` is not an array (the plain string/absent shape).
108
+ */
109
+ export function chatContentParts(content) {
110
+ if (!Array.isArray(content)) return null;
111
+ const parts = [];
112
+ for (const chunk of content) {
113
+ if (typeof chunk === 'string') {
114
+ parts.push({ kind: 'text', text: chunk });
115
+ } else if (chunk?.type === 'thinking') {
116
+ parts.push({ kind: 'reasoning', text: thinkingText(chunk.thinking) });
117
+ } else if (chunk?.type === 'text' && typeof chunk.text === 'string') {
118
+ parts.push({ kind: 'text', text: chunk.text });
119
+ }
120
+ }
121
+ return parts;
122
+ }
123
+
124
+ /**
125
+ * Content text, reasoning and reasoning source of one non-streaming message.
126
+ * `reasoning_content` keeps priority; the `reasoning` alias is read only under
127
+ * a shape that reports reasoning there; thinking chunks fill in when no field
128
+ * carried reasoning.
129
+ */
130
+ export function readChatMessage(message, { shape = null } = {}) {
131
+ const parts = chatContentParts(message?.content);
132
+ const content = parts
133
+ ? parts
134
+ .filter((part) => part.kind === 'text')
135
+ .map((part) => part.text)
136
+ .join('')
137
+ : typeof message?.content === 'string'
138
+ ? message.content
139
+ : '';
140
+ if (typeof message?.reasoning_content === 'string') {
141
+ return { content, reasoningContent: message.reasoning_content, reasoningSource: 'reasoning_content' };
142
+ }
143
+ if (shape?.readsReasoningAlias && typeof message?.reasoning === 'string') {
144
+ return { content, reasoningContent: message.reasoning, reasoningSource: 'reasoning' };
145
+ }
146
+ const thinking = parts?.filter((part) => part.kind === 'reasoning');
147
+ if (thinking?.length) {
148
+ return { content, reasoningContent: thinking.map((part) => part.text).join(''), reasoningSource: 'content_chunks' };
149
+ }
150
+ return { content, reasoningContent: null, reasoningSource: null };
151
+ }
@@ -7,18 +7,20 @@ import {
7
7
  writeXaiResponsesCacheTrace,
8
8
  } from './openai-compat-xai.mjs';
9
9
  import { createProviderReplay } from './lib/provider-replay.mjs';
10
-
11
- const reportedNumber = (value) =>
12
- value == null || (typeof value === 'string' && value.trim() === '') ? Number.NaN : Number(value);
10
+ import { reportedCostUsd } from './lib/usage-primitives.mjs';
11
+ import { stampStreamOutcome, STREAM_TRANSPORTS } from './lib/stream-outcome.mjs';
12
+ import { failingFinishReasonError } from './openai-compat-stream-common.mjs';
13
+ import {
14
+ COMPAT_REASONING_METADATA_KEY,
15
+ capturesShapeReasoning,
16
+ replayReasoningField,
17
+ } from './openai-compat-reasoning-field.mjs';
13
18
 
14
19
  export function compatReportedCostUsd(providerName, usage) {
15
- if (providerName === 'openrouter') {
16
- const cost = reportedNumber(usage?.cost);
17
- return Number.isFinite(cost) && cost >= 0 ? cost : undefined;
18
- }
20
+ if (providerName === 'openrouter') return reportedCostUsd(usage?.cost);
19
21
  if (providerName === 'xai') {
20
- const ticks = reportedNumber(usage?.cost_in_usd_ticks);
21
- return Number.isFinite(ticks) && ticks >= 0 ? Number((ticks * 1e-10).toFixed(8)) : undefined;
22
+ const ticks = reportedCostUsd(usage?.cost_in_usd_ticks);
23
+ return ticks === undefined ? undefined : Number((ticks * 1e-10).toFixed(8));
22
24
  }
23
25
  return undefined;
24
26
  }
@@ -77,12 +79,11 @@ export function traceCompatResponseUsage({
77
79
  });
78
80
  }
79
81
 
80
- // Responses-wire reported cost: a gateway `cost` (decimal USD) when present,
81
- // else xAI ticks. null/empty/negative is "not reported", never a reported $0.
82
+ // Responses-wire reported cost: xAI `cost_in_usd_ticks` when present, else a
83
+ // gateway `cost` (decimal USD). null/empty/negative is "not reported", never a
84
+ // reported $0.
82
85
  export function responsesReportedCostUsd(usage) {
83
- const cost = reportedNumber(usage?.cost);
84
- if (Number.isFinite(cost) && cost >= 0) return cost;
85
- return costUsdFromTicks(usage?.cost_in_usd_ticks);
86
+ return costUsdFromTicks(usage?.cost_in_usd_ticks) ?? reportedCostUsd(usage?.cost);
86
87
  }
87
88
 
88
89
  export function chatCompletionUsage(providerName, usage) {
@@ -136,11 +137,33 @@ export function normalizeCompatChatResponse({
136
137
  cacheRoutingKey,
137
138
  cacheRouting,
138
139
  replaysReasoningContent,
140
+ reasoningShape = null,
139
141
  }) {
140
142
  const response = assembled.response;
141
143
  const choice = response.choices[0];
142
144
  const toolCalls = assembled.toolCalls;
143
145
  const stopReason = choice?.finish_reason || null;
146
+ const failingFinish = failingFinishReasonError(stopReason, providerName);
147
+ if (failingFinish) {
148
+ const err = failingFinish;
149
+ const partialContent = assembled.content || '';
150
+ Object.assign(err, {
151
+ partialContent,
152
+ partialToolCalls: Array.isArray(toolCalls) && toolCalls.length ? toolCalls : undefined,
153
+ pendingToolUse: false,
154
+ partialModel: response.model || useModel,
155
+ ...(response.usage ? { partialUsage: chatCompletionUsage(providerName, response.usage) } : {}),
156
+ });
157
+ stampStreamOutcome(err, {
158
+ transport: STREAM_TRANSPORTS.NON_STREAMING,
159
+ provider: 'openai-compat',
160
+ terminalObserved: false,
161
+ continuation: true,
162
+ textObservedChars: partialContent.length,
163
+ toolCallsComplete: err.partialToolCalls?.length || 0,
164
+ });
165
+ throw err;
166
+ }
144
167
  if (
145
168
  (stopReason === 'length' && Array.isArray(toolCalls) && toolCalls.length > 0) ||
146
169
  stopReason === 'content_filter'
@@ -150,7 +173,7 @@ export function normalizeCompatChatResponse({
150
173
  code: 'PROVIDER_INCOMPLETE',
151
174
  providerIncomplete: true,
152
175
  finishReason: stopReason,
153
- partialContent: choice?.message?.content || '',
176
+ partialContent: assembled.content || '',
154
177
  partialToolCalls: toolCalls,
155
178
  model: response.model || useModel,
156
179
  responseId: response.id || null,
@@ -182,14 +205,30 @@ export function normalizeCompatChatResponse({
182
205
  cachedTokens: extractCompatCachedTokens(response.usage),
183
206
  });
184
207
  }
208
+ // Together/vLLM/Groq/OpenRouter report reasoning on `reasoning` or
209
+ // `reasoning_content`; Mistral reports it as thinking chunks inside
210
+ // `content`. Both are captured by the provider's own shape / the response
211
+ // shape, whatever the replay flag says.
212
+ const reasoningField = replayReasoningField(reasoningShape, assembled.reasoningSource);
185
213
  const capturesReasoningContent =
186
- providerName === 'deepseek' || providerName === 'xai' || providerName === 'mixdog-local' || replaysReasoningContent;
214
+ providerName === 'deepseek' ||
215
+ providerName === 'xai' ||
216
+ providerName === 'mixdog-local' ||
217
+ replaysReasoningContent ||
218
+ capturesShapeReasoning(reasoningShape, assembled.reasoningSource);
187
219
  const reasoningContent =
188
220
  capturesReasoningContent && typeof assembled.reasoningContent === 'string' ? assembled.reasoningContent : null;
189
221
  const reasoningDetails =
190
222
  providerName === 'openrouter' && Array.isArray(choice?.message?.reasoning_details)
191
223
  ? choice.message.reasoning_details
192
224
  : null;
225
+ // Replay sends reasoning back under the field it arrived on.
226
+ const providerMetadata = {
227
+ ...(reasoningDetails?.length ? { openrouter: { reasoning_details: reasoningDetails } } : {}),
228
+ ...(reasoningContent !== null && reasoningField
229
+ ? { [COMPAT_REASONING_METADATA_KEY]: { reasoningField } }
230
+ : {}),
231
+ };
193
232
  return {
194
233
  content: assembled.content || '',
195
234
  // Streamed chunks can omit `model`; fall back to the requested
@@ -205,11 +244,7 @@ export function normalizeCompatChatResponse({
205
244
  // instead of silently treating a truncated answer as complete.
206
245
  ...(stopReason === 'length' && (assembled.content || '').length > 0 ? { truncated: true } : {}),
207
246
  ...(reasoningContent !== null ? { reasoningContent } : {}),
208
- ...(reasoningDetails?.length
209
- ? {
210
- providerMetadata: { openrouter: { reasoning_details: reasoningDetails } },
211
- }
212
- : {}),
247
+ ...(Object.keys(providerMetadata).length ? { providerMetadata } : {}),
213
248
  usage: response.usage ? chatCompletionUsage(providerName, response.usage) : undefined,
214
249
  };
215
250
  }
@@ -309,8 +344,14 @@ export function normalizeXaiResponsesWebSocket({
309
344
  cacheLane,
310
345
  }) {
311
346
  const responseId = result.responseId || previousResponseId || null;
312
- const encryptedReasoningItems = encryptedXaiReasoningItems(result.responseItems);
313
- const providerReplay = createProviderReplay('xai-responses', result.responseItems);
347
+ // The WS send result drops the collector's `responseItems`; its own
348
+ // owner-tagged `providerReplay` (traceProvider 'xai') still carries every
349
+ // output item in order: encrypted reasoning and server-executed tool_search
350
+ // call/output pairs. Always taken, so they survive to the next turn as xAI
351
+ // requires.
352
+ const responseItems = result.responseItems ?? result.providerReplay?.items;
353
+ const encryptedReasoningItems = encryptedXaiReasoningItems(responseItems);
354
+ const providerReplay = createProviderReplay('xai-responses', responseItems);
314
355
  const encryptedReasoningHistory = xaiEncryptedReasoningHistory(opts, messages, encryptedReasoningItems);
315
356
  const rawUsage = result.usage?.raw || result.usage || null;
316
357
  const response = {
@@ -2,11 +2,18 @@
2
2
  // wire event type maps to one handler over the shared stream `state`; `ctx`
3
3
  // carries the label, the caller callbacks and the leaked-text relay.
4
4
  import { typedStatusFrom } from './retry-classifier.mjs';
5
- import { customToolCallFromResponseItem, nativeToolSearchCallFromArguments } from './custom-tool-wire.mjs';
5
+ import { applyCompatErrorContract } from './openai-compat-error-contract.mjs';
6
+ import {
7
+ customToolCallFromResponseItem,
8
+ nativeToolSearchCallFromArguments,
9
+ withToolCallNamespace,
10
+ } from './custom-tool-wire.mjs';
11
+ import { createRefusals } from './openai-ws-response-state/refusals.mjs';
6
12
  import { emitCompatToolCallOnce } from './openai-compat-stream-common.mjs';
7
13
  import { truncatedCompatStreamError, parseCompletedToolCallArgumentsJson } from './lib/openai-tool-args.mjs';
8
14
  import { incompleteReasonFromEvent, isMaxOutputIncompleteReason } from './lib/responses-terminal-fields.mjs';
9
15
  import { responsesUsage } from './openai-compat-response-normalization.mjs';
16
+ import { normalizeGatewayErrorDetail } from './provider-error-kind.mjs';
10
17
 
11
18
  // An incomplete response was still billed: carry its reported usage on the
12
19
  // error so the provider-boundary accounting records it.
@@ -34,16 +41,20 @@ function signal(ctx, kind) {
34
41
  // through the fatal-code deny-list / default-retry classification.
35
42
  function typedResponsesFailure(message, event) {
36
43
  const err = new Error(message);
37
- const detail = event?.response?.error || event?.error || null;
44
+ // A gateway's canonical error_type (OpenRouter's top-level `error_type`)
45
+ // replaces the lossy native code before anything classifies it.
46
+ const detail = normalizeGatewayErrorDetail(event?.response?.error || event?.error || null, event);
38
47
  const typed = typedStatusFrom(detail, event);
39
48
  if (typed) err.httpStatus = typed;
40
49
  const code = detail?.code ?? detail?.type ?? event?.code ?? null;
41
50
  if (code != null && code !== '') err.providerErrorCode = String(code);
42
51
  if (detail) err.providerError = detail;
43
52
  err.providerWireError = true;
44
- return err;
53
+ return applyCompatErrorContract(err, detail || (event?.code != null ? { code: event.code } : null));
45
54
  }
46
55
 
56
+ const streamLabel = (ctx) => ctx?.label || 'compat Responses';
57
+
47
58
  // Reconcile a COMPLETED function_call item into state.toolCalls: fill in the
48
59
  // id/name a streamed call may still be missing, or adopt the item as a new
49
60
  // call. `response.output_item.done` and the `response.completed` sweep see the
@@ -58,18 +69,22 @@ function reconcileCompatFunctionCallItem(state, item, label, onToolCall) {
58
69
  if (tc) {
59
70
  if (!tc.id && item.call_id) tc.id = item.call_id;
60
71
  if (!tc.name && item.name) tc.name = item.name;
72
+ withToolCallNamespace(tc, item);
61
73
  if (tc.id && tc.name) delete tc._pendingItemId;
62
74
  emitCompatToolCallOnce(state, tc, onToolCall);
63
75
  } else if (item.call_id && item.name) {
64
- const call = {
65
- id: item.call_id,
66
- name: item.name,
67
- arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, {
76
+ const call = withToolCallNamespace(
77
+ {
68
78
  id: item.call_id,
69
79
  name: item.name,
70
- finishReason: 'done',
71
- }),
72
- };
80
+ arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, {
81
+ id: item.call_id,
82
+ name: item.name,
83
+ finishReason: 'done',
84
+ }),
85
+ },
86
+ item
87
+ );
73
88
  state.toolCalls.push(call);
74
89
  emitCompatToolCallOnce(state, call, onToolCall);
75
90
  }
@@ -78,6 +93,9 @@ function reconcileCompatFunctionCallItem(state, item, label, onToolCall) {
78
93
 
79
94
  function pushToolSearchCall(state, item, ctx) {
80
95
  if (item?.type !== 'tool_search_call') return;
96
+ // Server-executed search already ran inside the response; it stays in
97
+ // providerReplay only and is never a local load_tool dispatch.
98
+ if (item.execution === 'server') return;
81
99
  const callId = item.call_id || item.id || '';
82
100
  if (!callId || state.toolCalls.some((call) => call.id === callId)) return;
83
101
  const searchArgs =
@@ -162,10 +180,10 @@ function onReasoningDelta(event, state, ctx) {
162
180
  function onOutputItemAdded(event, state, ctx) {
163
181
  const type = event.item?.type;
164
182
  if (type === 'function_call') {
165
- state.pendingCalls.set(event.item.id || '', {
166
- name: event.item.name || '',
167
- callId: event.item.call_id || '',
168
- });
183
+ state.pendingCalls.set(
184
+ event.item.id || '',
185
+ withToolCallNamespace({ name: event.item.name || '', callId: event.item.call_id || '' }, event.item)
186
+ );
169
187
  state.toolTracker?.mark(event.item);
170
188
  state.toolInFlight = true;
171
189
  } else if (type === 'custom_tool_call' || type === 'tool_search_call') {
@@ -191,26 +209,47 @@ function onToolInputDelta(event, state, ctx) {
191
209
  function onFunctionCallArgumentsDone(event, state, ctx) {
192
210
  const itemId = event.item_id || '';
193
211
  const pending = state.pendingCalls.get(itemId);
194
- const call = {
195
- id: pending?.callId || event.call_id || '',
196
- name: pending?.name || event.name || '',
197
- // `*.done` ⇒ arguments are complete; a parse failure is
198
- // deterministic bad JSON (permanent), not stream truncation.
199
- arguments: parseCompletedToolCallArgumentsJson(event.arguments, ctx.label, {
200
- id: pending?.callId || event.call_id,
201
- name: pending?.name || event.name,
202
- finishReason: 'done',
203
- }),
204
- _pendingItemId: itemId,
205
- };
212
+ const call = withToolCallNamespace(
213
+ {
214
+ id: pending?.callId || event.call_id || '',
215
+ name: pending?.name || event.name || '',
216
+ // `*.done` ⇒ arguments are complete; a parse failure is
217
+ // deterministic bad JSON (permanent), not stream truncation.
218
+ arguments: parseCompletedToolCallArgumentsJson(event.arguments, ctx.label, {
219
+ id: pending?.callId || event.call_id,
220
+ name: pending?.name || event.name,
221
+ finishReason: 'done',
222
+ }),
223
+ _pendingItemId: itemId,
224
+ },
225
+ pending
226
+ );
206
227
  state.toolCalls.push(call);
207
228
  if (call.id && call.name) delete call._pendingItemId;
208
229
  emitCompatToolCallOnce(state, call, ctx.onToolCall);
209
230
  signal(ctx, 'tool');
210
231
  }
211
232
 
233
+ // Refusal parts (streamed deltas, done text, final message parts) fold into
234
+ // one typed refusal on state.refusals; the stream collector turns it into a
235
+ // `stopReason:'refusal'` result instead of an empty success.
236
+ const refusalsOf = (state) => (state.refusals ||= createRefusals());
237
+
238
+ function onRefusalDelta(event, state, ctx) {
239
+ state.sawOutput = true;
240
+ refusalsOf(state).delta(event);
241
+ signal(ctx, 'semantic');
242
+ }
243
+
244
+ function onRefusalDone(event, state, ctx) {
245
+ state.sawOutput = true;
246
+ refusalsOf(state).done(event);
247
+ signal(ctx, 'semantic');
248
+ }
249
+
212
250
  function onOutputItemDone(event, state, ctx) {
213
251
  const item = event.item || {};
252
+ if (item.type === 'message') refusalsOf(state).absorbMessage(item);
214
253
  if (item.type === 'function_call') {
215
254
  const itemId = reconcileCompatFunctionCallItem(state, item, ctx.label, ctx.onToolCall);
216
255
  // Drop the resolved function item from pendingCalls before
@@ -289,6 +328,7 @@ function onCompleted(event, state, ctx) {
289
328
  }
290
329
 
291
330
  function onDone(event, state, ctx) {
331
+ const label = streamLabel(ctx);
292
332
  if (!event.response || event.response.status === 'completed') {
293
333
  state.completed = true;
294
334
  // A stream that never emits response.completed: this frame carries usage.
@@ -298,7 +338,7 @@ function onDone(event, state, ctx) {
298
338
  if (event.response.status === 'failed') {
299
339
  const msg = event.response?.error?.message || 'response.done failed';
300
340
  throw withIncompleteUsage(
301
- typedResponsesFailure(`xAI Responses stream response.done failed: ${msg}`, event),
341
+ typedResponsesFailure(`${label} stream response.done failed: ${msg}`, event),
302
342
  event,
303
343
  state
304
344
  );
@@ -306,27 +346,31 @@ function onDone(event, state, ctx) {
306
346
  if (event.response.status === 'incomplete') {
307
347
  const reason = incompleteReasonFromEvent(event);
308
348
  if (isMaxOutputIncompleteReason(reason)) return settleMaxOutputIncomplete(event, state, ctx, reason);
309
- throw withIncompleteUsage(new Error(`xAI Responses stream response.done incomplete: ${reason}`), event, state);
349
+ throw withIncompleteUsage(new Error(`${label} stream response.done incomplete: ${reason}`), event, state);
310
350
  }
311
351
  }
312
352
 
313
- function onFailed(event, state) {
353
+ function onFailed(event, state, ctx) {
314
354
  const msg = event.response?.error?.message || event.error?.message || event.message || 'response.failed';
315
355
  // The wire event's OWN typed status/code is preserved verbatim. A
316
356
  // forbidden/unknown failure is never coerced into a synthetic 500:
317
357
  // without typed evidence it stays unclassified and is surfaced.
318
- throw withIncompleteUsage(typedResponsesFailure(`xAI Responses stream response.failed: ${msg}`, event), event, state);
358
+ throw withIncompleteUsage(
359
+ typedResponsesFailure(`${streamLabel(ctx)} stream response.failed: ${msg}`, event),
360
+ event,
361
+ state
362
+ );
319
363
  }
320
364
 
321
365
  function onIncomplete(event, state, ctx) {
322
366
  const reason = incompleteReasonFromEvent(event);
323
367
  if (isMaxOutputIncompleteReason(reason)) return settleMaxOutputIncomplete(event, state, ctx, reason);
324
- throw withIncompleteUsage(new Error(`xAI Responses stream response.incomplete: ${reason}`), event, state);
368
+ throw withIncompleteUsage(new Error(`${streamLabel(ctx)} stream response.incomplete: ${reason}`), event, state);
325
369
  }
326
370
 
327
- function onError(event) {
371
+ function onError(event, _state, ctx) {
328
372
  const msg = event.message || event.error?.message || 'unknown';
329
- throw typedResponsesFailure(`xAI Responses stream error: ${msg}`, event);
373
+ throw typedResponsesFailure(`${streamLabel(ctx)} stream error: ${msg}`, event);
330
374
  }
331
375
 
332
376
  const RESPONSES_EVENT_HANDLERS = new Map([
@@ -334,6 +378,8 @@ const RESPONSES_EVENT_HANDLERS = new Map([
334
378
  ['response.output_text.delta', onOutputTextDelta],
335
379
  ['response.reasoning_text.delta', onReasoningDelta],
336
380
  ['response.reasoning_summary_text.delta', onReasoningDelta],
381
+ ['response.refusal.delta', onRefusalDelta],
382
+ ['response.refusal.done', onRefusalDone],
337
383
  ['response.output_item.added', onOutputItemAdded],
338
384
  ['response.function_call_arguments.delta', onToolInputDelta],
339
385
  ['response.custom_tool_call_input.delta', onToolInputDelta],