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
@@ -0,0 +1,512 @@
1
+ /**
2
+ * wire-route.mjs — which wire a gateway model is reached on.
3
+ *
4
+ * A gateway that speaks several wires (OpenRouter, OpenCode Go, Command Code,
5
+ * DeepSeek) sends each model over its brand-native or best-supported wire:
6
+ * 'messages' (Anthropic Messages), 'responses' (OpenAI Responses), 'chat'
7
+ * (Chat Completions) or 'gemini' (generateContent). One answer per
8
+ * provider+model, in this order:
9
+ *
10
+ * 1. an explicit per-model user override (provider config `modelWires`),
11
+ * 2. catalog / endpoint metadata (models.dev SDK package, the roster's
12
+ * advertised endpoints),
13
+ * 3. the provider's model-family table,
14
+ * 4. the provider default.
15
+ *
16
+ * Every tier is limited to the wires the gateway actually serves for that
17
+ * model (`offered`, narrowed by advertised endpoints), so no tier can guess an
18
+ * endpoint the gateway does not offer.
19
+ *
20
+ * A session pins its answer (`session.wireRoute`) before its first request,
21
+ * so the tool snapshot, history lowering, request serialization and usage
22
+ * normalization of every later turn follow the same wire; an existing session
23
+ * keeps the wire it started on even after this table changes.
24
+ *
25
+ * `nativeDeferredTools` marks, per wire, whether the gateway is verified to
26
+ * carry provider-native deferred tools (defer_loading + tool_reference on
27
+ * Messages, tool_search output on Responses). It is OFF for every gateway
28
+ * until verified live. A route pinned before its session's first request
29
+ * records the flag (`nativeDeferredTools: true`); the session's tool surface
30
+ * follows that record, so flipping a flag later only affects new sessions.
31
+ */
32
+
33
+ export const WIRES = Object.freeze(['messages', 'responses', 'chat', 'gemini']);
34
+
35
+ const GO_RESPONSES = /^(?:muse-spark-|gpt-|grok-)/i;
36
+ const GO_MESSAGES = /^(?:minimax-|qwen|claude-)/i;
37
+ const GO_GEMINI = /^gemini-/i;
38
+ // Before Claude joined the cold-catalog Messages prefixes.
39
+ const GO_MESSAGES_BEFORE_CLAUDE = /^(?:minimax-|qwen)/i;
40
+
41
+ // Unverified: no gateway wire carries native deferred tools yet.
42
+ const nativeDeferredOff = () => ({ messages: false, responses: false });
43
+
44
+ export const PROFILES = Object.freeze({
45
+ // OpenRouter serves every model on /chat/completions, /responses and
46
+ // /messages; Claude is native on Messages, OpenAI GPT/o-series on Responses.
47
+ openrouter: {
48
+ offered: ['chat', 'messages', 'responses'],
49
+ nativeDeferredTools: nativeDeferredOff(),
50
+ families: [
51
+ { match: /^~?anthropic\//i, wire: 'messages' },
52
+ { match: /^(?:openai\/(?:gpt-|o\d)|~openai\/)/i, wire: 'responses' },
53
+ ],
54
+ defaultWire: 'chat',
55
+ legacy: () => 'chat',
56
+ },
57
+ // OpenCode Go answers each brand on one wire (models.dev names it per model;
58
+ // the prefixes are the cold-catalog fallback): Gemini on its generateContent
59
+ // endpoint, Claude / MiniMax / Qwen on Messages, GPT / Grok / Muse on
60
+ // Responses, the rest on Chat.
61
+ 'opencode-go': {
62
+ offered: ['chat', 'responses', 'messages', 'gemini'],
63
+ nativeDeferredTools: nativeDeferredOff(),
64
+ families: [
65
+ { match: GO_RESPONSES, wire: 'responses' },
66
+ { match: GO_MESSAGES, wire: 'messages' },
67
+ { match: GO_GEMINI, wire: 'gemini' },
68
+ ],
69
+ defaultWire: 'chat',
70
+ // Sessions created before the Gemini wire existed sent Gemini models to Chat.
71
+ legacy: ({ model, catalogWire }) => {
72
+ if (catalogWire && catalogWire !== 'gemini') return catalogWire;
73
+ if (GO_RESPONSES.test(model)) return 'responses';
74
+ return GO_MESSAGES_BEFORE_CLAUDE.test(model) ? 'messages' : 'chat';
75
+ },
76
+ },
77
+ // Command Code declares per-model endpoints: GPT / Muse / Grok prefer
78
+ // Responses when advertised, otherwise Chat, Messages when it is the only
79
+ // wire, and a Responses-only model stays reachable.
80
+ 'command-code-oauth': {
81
+ offered: ['chat', 'messages', 'responses'],
82
+ nativeDeferredTools: nativeDeferredOff(),
83
+ families: [
84
+ { match: /(?:^|\/)(?:gpt-|muse-|grok-)/i, wire: 'responses' },
85
+ // Claude answers on /messages only: it keeps that wire even when the
86
+ // roster cannot be read (the other families wait for the roster).
87
+ { match: /(?:^|\/)claude-/i, wire: 'messages', cold: true },
88
+ ],
89
+ defaultWire: 'chat',
90
+ preference: ['chat', 'messages', 'responses'],
91
+ legacy: ({ endpoints }) => (endpoints.includes('chat') || !endpoints.includes('messages') ? 'chat' : 'messages'),
92
+ },
93
+ // DeepSeek's Anthropic endpoint carries thinking + tool blocks for agent/tool
94
+ // sessions; Chat stays the wire for tool-less one-shot requests. It has no
95
+ // Responses endpoint.
96
+ deepseek: {
97
+ offered: ['chat', 'messages'],
98
+ nativeDeferredTools: nativeDeferredOff(),
99
+ families: [{ match: /^deepseek-/i, wire: 'messages', agentOnly: true }],
100
+ defaultWire: 'chat',
101
+ legacy: () => 'chat',
102
+ },
103
+ });
104
+
105
+ // User-defined providers (`custom-<uuid>`): one profile per configured
106
+ // provider, registered when the provider is built (customWireProfile).
107
+ const CUSTOM_PROFILES = new Map();
108
+
109
+ function profileOf(provider) {
110
+ const name = String(provider || '');
111
+ return Object.hasOwn(PROFILES, name) ? PROFILES[name] : CUSTOM_PROFILES.get(name) || null;
112
+ }
113
+
114
+ /**
115
+ * The profile of a user-defined OpenAI-compatible provider: the wires its
116
+ * endpoint is declared to serve (`wires`, default the protocol's own wire),
117
+ * the protocol's wire as default and as the wire every existing session
118
+ * started on. No model-family table: only the per-model `modelWires`
119
+ * override picks another wire.
120
+ */
121
+ export function customWireProfile({ protocolWire, wires = null }) {
122
+ const offered = Array.isArray(wires) && wires.length ? [...wires] : [protocolWire];
123
+ return {
124
+ offered,
125
+ nativeDeferredTools: nativeDeferredOff(),
126
+ families: [],
127
+ defaultWire: protocolWire,
128
+ legacy: () => protocolWire,
129
+ };
130
+ }
131
+
132
+ /** Register (or replace) the profile of user-defined provider `provider`. */
133
+ export function registerWireProfile(provider, profile) {
134
+ CUSTOM_PROFILES.set(String(provider || ''), profile);
135
+ }
136
+
137
+ /** Whether `provider` routes models through this table. */
138
+ export function hasWireProfile(provider) {
139
+ return profileOf(provider) !== null;
140
+ }
141
+
142
+ /** Whether `provider` serves `wire` at all. */
143
+ export function providerOffersWire(provider, wire) {
144
+ return Boolean(profileOf(provider)?.offered.includes(wire));
145
+ }
146
+
147
+ /** Whether `provider`'s `wire` is verified to carry native deferred tools. */
148
+ export function wireSupportsNativeDeferredTools(provider, wire) {
149
+ return profileOf(provider)?.nativeDeferredTools?.[wire] === true;
150
+ }
151
+
152
+ const NATIVE_DEFERRED_FAMILY = Object.freeze({ messages: 'anthropic', responses: 'openai' });
153
+
154
+ /**
155
+ * The native deferred-tool family ('anthropic' | 'openai') a pinned route
156
+ * gives `provider`, or '' — a route for another provider, one pinned without
157
+ * verified support, or a wire with no native contract (Chat, Gemini).
158
+ */
159
+ export function nativeDeferredFamilyForRoute(provider, route) {
160
+ if (!route || route.nativeDeferredTools !== true) return '';
161
+ const name = String(provider || '')
162
+ .trim()
163
+ .toLowerCase();
164
+ if (!name || String(route.provider || '').toLowerCase() !== name) return '';
165
+ return NATIVE_DEFERRED_FAMILY[route.wire] || '';
166
+ }
167
+
168
+ /**
169
+ * @param {string} provider
170
+ * @param {string} model the routing id (an alias slug stays the alias)
171
+ * @param {object} [ctx]
172
+ * @param {string|null} [ctx.override] the user's per-model wire
173
+ * @param {string|null} [ctx.catalogWire] the catalog's wire for this model
174
+ * @param {string[]|null} [ctx.endpoints] the wires the gateway advertises for this model
175
+ * @param {boolean} [ctx.known] false when no metadata describes the model at all
176
+ * @param {boolean} [ctx.agent] an agent/tool session (or a send carrying tools)
177
+ * @param {boolean} [ctx.legacy] the wire an existing session started on before this table
178
+ * @param {string[]} [ctx.exclude] wires that must not be chosen (the one a send was just refused on)
179
+ * @returns {{ wire: string, profileId: string, source: string }|null} null for a
180
+ * provider without a profile, or a model no offered wire serves
181
+ */
182
+ export function resolveWireRoute(
183
+ provider,
184
+ model,
185
+ {
186
+ override = null,
187
+ catalogWire = null,
188
+ endpoints = null,
189
+ known = true,
190
+ agent = false,
191
+ legacy = false,
192
+ keep = null,
193
+ exclude = [],
194
+ } = {}
195
+ ) {
196
+ const profile = profileOf(provider);
197
+ if (!profile) return null;
198
+ const id = String(model || '');
199
+ const route = (wire, source) => ({ wire, profileId: `${provider}:${wire}`, source });
200
+ const advertised = (
201
+ Array.isArray(endpoints) ? profile.offered.filter((wire) => endpoints.includes(wire)) : profile.offered
202
+ ).filter((wire) => !exclude.includes(wire));
203
+ const usable = (wire) => advertised.includes(wire);
204
+ // A wire the session already pinned stays while the model is still offered
205
+ // on it (a model nothing describes keeps its pin: no metadata, no change).
206
+ if (keep && (known === false ? profile.offered : advertised).includes(keep)) return route(keep, 'pinned');
207
+ // Nothing describes this model (no roster row, no cached row): the
208
+ // gateway's conventional wire, flagged so a session never pins the guess.
209
+ // A model with no advertised wire at all is not routable.
210
+ const unknown = () => {
211
+ // A family that is certain without metadata (`cold`: Claude on Command
212
+ // Code answers on Messages only) outranks the conventional wire.
213
+ const cold = profile.families.find((rule) => rule.cold === true && rule.match.test(id) && usable(rule.wire));
214
+ const wire =
215
+ cold?.wire ||
216
+ (usable(profile.defaultWire) ? profile.defaultWire : (profile.preference || profile.offered).find(usable));
217
+ return wire ? route(wire, 'unknown') : null;
218
+ };
219
+ if (legacy) {
220
+ if (known === false) return unknown();
221
+ // The wire a pre-table session started on, while the model still offers
222
+ // it; otherwise the fresh resolution below (never an unadvertised wire).
223
+ const legacyWire = profile.legacy({ model: id, catalogWire: usable(catalogWire) ? catalogWire : null, endpoints: advertised });
224
+ if (usable(legacyWire)) return route(legacyWire, 'legacy');
225
+ }
226
+ if (override && usable(override)) return route(override, 'override');
227
+ if (known === false) return unknown();
228
+ if (catalogWire && usable(catalogWire)) return route(catalogWire, 'catalog');
229
+ if (Array.isArray(endpoints) && advertised.length === 1) return route(advertised[0], 'endpoints');
230
+ const family = profile.families.find(
231
+ (rule) => rule.match.test(id) && (rule.agentOnly !== true || agent) && usable(rule.wire)
232
+ );
233
+ if (family) return route(family.wire, 'family');
234
+ if (usable(profile.defaultWire)) return route(profile.defaultWire, 'default');
235
+ const preferred = (profile.preference || profile.offered).find(usable);
236
+ return preferred ? route(preferred, 'endpoints') : null;
237
+ }
238
+
239
+ /**
240
+ * The route one send uses: the session's pinned route when it names this
241
+ * provider and model, else a fresh resolution (a send carrying tools counts as
242
+ * an agent/tool request). Resolved before the request is built, so lowering,
243
+ * serialization and usage normalization all follow one answer.
244
+ */
245
+ export async function sendWireRoute(provider, model, tools, sendOpts, messages = null) {
246
+ const route = await resolveSendRoute(provider, model, tools, sendOpts, messages);
247
+ // A provider with a wire table that offers the model nowhere: nothing is sent.
248
+ if (!route && hasWireProfile(provider.name)) throw modelNotRoutableError(provider.name, model);
249
+ return route;
250
+ }
251
+
252
+ // Status codes a gateway answers when it does not serve the model on the wire
253
+ // asked: 405 / 501 name the endpoint itself; 400 / 404 / 415 / 422 count only
254
+ // when the body also says the endpoint or route is unsupported. Auth (401,
255
+ // 403), quota / billing (402, 429) and server errors never qualify.
256
+ const ENDPOINT_STATUSES = new Set([405, 501]);
257
+ const REJECTION_STATUSES = new Set([400, 404, 415, 422]);
258
+ const ENDPOINT_WORDS = /\b(?:endpoints?|routes?)\b|\/(?:v1\/)?(?:messages|responses|chat\/completions)\b|chat completions/i;
259
+ const UNSUPPORTED_WORDS =
260
+ /\bunsupported\b|not (?:be )?(?:supported|available|served|implemented)|(?:does not|doesn't|do not|don't) (?:support|serve)|only (?:available|supported|served)|wrong endpoint|use (?:the )?\/?(?:v1\/)?(?:messages|responses|chat\/completions)\b/i;
261
+ // A typed code / type that names an auth, quota, billing or parameter failure
262
+ // is never a wire rejection, whatever its message says about endpoints.
263
+ const NON_WIRE_ERROR_TYPE =
264
+ /auth|permission|forbidden|api_?key|token|quota|billing|credit|balance|payment|insufficient|rate_?limit|too_many|overload|capacity|(?:unsupported|unknown|unrecognized|invalid)_?(?:parameter|param|field|argument|value)|invalid_?(?:request_)?param|context_?length|max_?tokens/i;
265
+ // The same families in message wording.
266
+ const NON_WIRE_ERROR_TEXT =
267
+ /\b(?:unsupported|unknown|unrecognized|unexpected|invalid|extra|not permitted|not allowed)\s+(?:request\s+)?(?:parameters?|params?|fields?|arguments?|propert(?:y|ies)|options?|values?|keys?)\b|\bparameters?\b[^.]{0,40}\b(?:not supported|unsupported|not allowed)|\bquota\b|\bbilling\b|\bcredits?\b|\bbalance\b|\binsufficient\b|rate[ -]?limit|too many requests|unauthori[sz]ed|\bforbidden\b|invalid api key|api key|\bpayment\b|\bsubscription\b/i;
268
+
269
+ const errorTypes = (error) =>
270
+ [
271
+ error.code,
272
+ error.type,
273
+ error.providerErrorCode,
274
+ error.providerErrorType,
275
+ error.error?.code,
276
+ error.error?.type,
277
+ error.providerError?.code,
278
+ error.providerError?.type,
279
+ ].filter((part) => typeof part === 'string');
280
+
281
+ /**
282
+ * Whether `error` is a clear "this model is not served on this wire"
283
+ * rejection — the only failure a send may answer by switching wire. Typed
284
+ * HTTP evidence only; an aborted, stalled or already-streaming failure
285
+ * (anything that exposed output) never qualifies.
286
+ */
287
+ export function isWireUnsupportedError(error) {
288
+ if (!error || typeof error !== 'object') return false;
289
+ if (error.liveTextEmitted === true || error.emittedToolCall === true || error.unsafeToRetry === true) return false;
290
+ if (error.streamStalled === true || error.name === 'AbortError') return false;
291
+ if (error.quotaExhausted === true || error.reauthRequired === true) return false;
292
+ // A body that points at one request field (`param`) is a parameter error.
293
+ if (typeof error.param === 'string' || typeof error.error?.param === 'string') return false;
294
+ if (errorTypes(error).some((type) => NON_WIRE_ERROR_TYPE.test(type))) return false;
295
+ const status = Number(error.status ?? error.httpStatus ?? error.statusCode ?? error.response?.status);
296
+ const text = [error.message, error.error?.message, error.providerError?.message, error.error]
297
+ .filter((part) => typeof part === 'string')
298
+ .join(' ');
299
+ if (NON_WIRE_ERROR_TEXT.test(text)) return false;
300
+ if (ENDPOINT_STATUSES.has(status)) return true;
301
+ if (!REJECTION_STATUSES.has(status)) return false;
302
+ return ENDPOINT_WORDS.test(text) && UNSUPPORTED_WORDS.test(text);
303
+ }
304
+
305
+ // The send options with the output callbacks wrapped: `emitted()` turns true
306
+ // as soon as the caller was shown text, reasoning or a tool call.
307
+ function trackOutput(sendOpts) {
308
+ let emitted = false;
309
+ const wrap = (fn, shows = () => true) =>
310
+ typeof fn === 'function'
311
+ ? (...args) => {
312
+ if (shows(...args)) emitted = true;
313
+ return fn(...args);
314
+ }
315
+ : fn;
316
+ const opts = { ...(sendOpts || {}) };
317
+ opts.onTextDelta = wrap(opts.onTextDelta);
318
+ opts.onToolCall = wrap(opts.onToolCall);
319
+ opts.onStreamDelta = wrap(opts.onStreamDelta, (kind) => kind === 'text' || kind === 'reasoning' || kind === 'tool');
320
+ return { opts, emitted: () => emitted };
321
+ }
322
+
323
+ /**
324
+ * One send on its resolved route, with at most one switch of wire: when the
325
+ * gateway clearly rejects the model on that wire before anything reached the
326
+ * caller, the same request goes once more on the next wire the model is
327
+ * served on, and the session records the new route (history written on the
328
+ * old wire is lowered, as for any reroute). Never on an auth, quota, abort or
329
+ * mid-stream failure, and never a second time.
330
+ *
331
+ * @param {(wire: string|undefined, history: object[], opts: object) => Promise<object>} dispatch
332
+ * sends `history` on `wire` through the provider's engine for that wire
333
+ */
334
+ export async function sendOnRoute(provider, model, tools, sendOpts, messages, dispatch) {
335
+ const route = await sendWireRoute(provider, model, tools, sendOpts, messages);
336
+ const opts = withoutWireSwitches(sendOpts);
337
+ const tracked = trackOutput(opts);
338
+ try {
339
+ const result = await dispatch(route?.wire, lowerHistoryForRoute(messages, route), tracked.opts);
340
+ // A route re-resolved on this send (its pinned wire was dropped from the
341
+ // provider's config) is reported back like a refusal reroute below.
342
+ if (route?.source === 'reroute' && result && typeof result === 'object' && !Object.isFrozen(result)) {
343
+ result.wireReroute = route;
344
+ }
345
+ return result;
346
+ } catch (error) {
347
+ if (!route || tracked.emitted() || opts.signal?.aborted || !isWireUnsupportedError(error)) throw error;
348
+ const agent = Array.isArray(tools) && tools.length > 0;
349
+ const next = (await provider.resolveWireRoute(model, { agent, exclude: [route.wire] })) || null;
350
+ if (!next || next.wire === route.wire) throw error;
351
+ const session = sendOpts?.session;
352
+ const rerouted = {
353
+ provider: provider.name,
354
+ model,
355
+ ...next,
356
+ source: 'reroute',
357
+ reroutedFrom: route.wire,
358
+ reroutedReason: 'unsupported',
359
+ loweredAssistantCount: countAssistants(session?.messages ?? messages),
360
+ };
361
+ // The pin names its own provider and model, so a projected session (the
362
+ // model proxy's PC side carries no identity fields) is recognised by it.
363
+ if (pinMatches(session?.wireRoute, provider.name, model)) session.wireRoute = rerouted;
364
+ const result = await dispatch(rerouted.wire, lowerHistoryForRoute(messages, rerouted), opts);
365
+ // The authoritative route travels back with the result, for a caller
366
+ // whose session is not the object updated above (a proxied send).
367
+ if (result && typeof result === 'object' && !Object.isFrozen(result)) result.wireReroute = rerouted;
368
+ return result;
369
+ }
370
+ }
371
+
372
+ const pinMatches = (pin, providerName, model) => Boolean(pin) && pin.provider === providerName && pin.model === model;
373
+
374
+ function modelNotRoutableError(provider, model) {
375
+ return Object.assign(new Error(`[${provider}] model ${model} is not routable: no wire it is served on is offered`), {
376
+ code: 'MODEL_NOT_ROUTABLE',
377
+ provider,
378
+ model,
379
+ });
380
+ }
381
+
382
+ /**
383
+ * Strip the competing wire switches from send options: the resolved route is
384
+ * the only authority on which wire a request goes out on.
385
+ */
386
+ export function withoutWireSwitches(sendOpts) {
387
+ const { compatWireApi: _wire, responsesTransport: _transport, ...rest } = sendOpts || {};
388
+ return rest;
389
+ }
390
+
391
+ // Every message field a provider adapter replays as wire-native state.
392
+ const WIRE_REPLAY_FIELDS = [
393
+ 'providerReplay',
394
+ 'reasoning',
395
+ 'thinkingBlocks',
396
+ 'assistantBlocks',
397
+ 'reasoningItems',
398
+ 'reasoningContent',
399
+ 'providerMetadata',
400
+ ];
401
+
402
+ const countAssistants = (messages) =>
403
+ Array.isArray(messages) ? messages.filter((message) => message?.role === 'assistant').length : 0;
404
+
405
+ /**
406
+ * History as the route's wire may see it. A rerouted session (its pinned wire
407
+ * was no longer offered) carries `loweredAssistantCount`: the assistant turns
408
+ * recorded on the old wire. Their wire-native replay (reasoning, thinking
409
+ * blocks, native items) is dropped; turns produced on the new wire keep theirs.
410
+ */
411
+ export function lowerHistoryForRoute(messages, route) {
412
+ const count = route?.source === 'reroute' ? route.loweredAssistantCount : 0;
413
+ if (!(count > 0) || !Array.isArray(messages)) return messages;
414
+ let seen = 0;
415
+ return messages.map((message) => {
416
+ if (message?.role !== 'assistant' || seen++ >= count) return message;
417
+ if (!WIRE_REPLAY_FIELDS.some((field) => field in message)) return message;
418
+ const plain = { ...message };
419
+ for (const field of WIRE_REPLAY_FIELDS) delete plain[field];
420
+ return plain;
421
+ });
422
+ }
423
+
424
+ async function resolveSendRoute(provider, model, tools, sendOpts, messages) {
425
+ const agent = Array.isArray(tools) && tools.length > 0;
426
+ // The session's current pin outranks a copy carried in the send options: a
427
+ // reroute updates the session, and later sends of the same turn reuse opts.
428
+ const sessionPin = sendOpts?.session?.wireRoute;
429
+ const pinned = pinMatches(sessionPin, provider.name, model) ? sessionPin : (sendOpts?.wireRoute ?? sessionPin);
430
+ if (pinMatches(pinned, provider.name, model)) {
431
+ // The pin stands while the model's current endpoints still offer its wire
432
+ // (the provider may have been edited to drop it); otherwise the route is
433
+ // resolved fresh (not legacy) and the reroute is recorded.
434
+ const current = (await provider.resolveWireRoute(model, { agent, keep: pinned.wire })) || null;
435
+ if (current?.source === 'pinned') return pinned;
436
+ if (current && current.source !== 'unknown') {
437
+ const session = sendOpts?.session;
438
+ // An explicit reroute: recorded on the pin, with the history already
439
+ // written on the old wire marked for lowering.
440
+ const repinned = {
441
+ provider: provider.name,
442
+ model,
443
+ ...current,
444
+ source: 'reroute',
445
+ reroutedFrom: pinned.wire,
446
+ loweredAssistantCount: countAssistants(session?.messages ?? messages),
447
+ };
448
+ if (session?.wireRoute === pinned) session.wireRoute = repinned;
449
+ return repinned;
450
+ }
451
+ return current;
452
+ }
453
+ // A session created before this table that already talked to its model keeps
454
+ // its wire even when the pin could not resolve (no metadata yet) and the
455
+ // metadata recovered by this send: resolve as legacy and pin it now.
456
+ const legacySession = legacySessionOf(sendOpts?.session, provider.name, model);
457
+ const route = (await provider.resolveWireRoute(model, legacySession ? { agent, legacy: true } : { agent })) || null;
458
+ if (legacySession && route && route.source !== 'unknown' && legacySession.wireRoute === undefined) {
459
+ legacySession.wireRoute = { provider: provider.name, model, ...route };
460
+ return legacySession.wireRoute;
461
+ }
462
+ return route;
463
+ }
464
+
465
+ // `wireRoute` is absent (not null) on a session created before the table.
466
+ const isLegacySession = (subject) => subject.wireRoute === undefined && hasAssistantHistory(subject);
467
+
468
+ // The session of this send when it is an existing one for this provider and model.
469
+ function legacySessionOf(candidate, providerName, model) {
470
+ return candidate && candidate.provider === providerName && candidate.model === model && isLegacySession(candidate)
471
+ ? candidate
472
+ : null;
473
+ }
474
+
475
+ const hasAssistantHistory = (session) =>
476
+ Array.isArray(session?.messages) && session.messages.some((message) => message?.role === 'assistant');
477
+
478
+ /**
479
+ * Pin the session's wire before its turn reaches the request boundary.
480
+ * `session.wireRoute` is null on a session created with this table (resolved
481
+ * fresh) and absent on one created before it: such a session that already
482
+ * talked to its model keeps the wire it started on. A route change (another
483
+ * provider or model) resolves fresh. A single-wire adapter pins nothing, and
484
+ * a resolution that failed or had no metadata is not pinned — the send
485
+ * resolves again and surfaces the real failure.
486
+ *
487
+ * Only a route pinned before the session's first answered request records
488
+ * verified native deferred-tool support: a session that already talked on
489
+ * the bridge keeps it.
490
+ */
491
+ export async function pinSessionWireRoute(session, provider) {
492
+ if (!session?.provider || !session.model) return null;
493
+ const current = session.wireRoute;
494
+ if (current && current.provider === session.provider && current.model === session.model) return current;
495
+ if (typeof provider?.resolveWireRoute !== 'function') return null;
496
+ // Decided before any await: the turn appends its own messages afterwards.
497
+ const answered = hasAssistantHistory(session);
498
+ const legacy = current === undefined && answered;
499
+ const { provider: providerName, model } = session;
500
+ let route;
501
+ try {
502
+ route = await provider.resolveWireRoute(model, { agent: true, legacy });
503
+ } catch {
504
+ return null;
505
+ }
506
+ if (!route || route.source === 'unknown') return null;
507
+ // The route changed while resolving: the newer route pins on its own turn.
508
+ if (session.provider !== providerName || session.model !== model) return null;
509
+ const nativeDeferred = !answered && wireSupportsNativeDeferredTools(providerName, route.wire);
510
+ session.wireRoute = { provider: providerName, model, ...route, ...(nativeDeferred ? { nativeDeferredTools: true } : {}) };
511
+ return session.wireRoute;
512
+ }