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,172 @@
1
+ // Shared by openai-compat-responses-native.test.mjs and the one-off generator
2
+ // that produced openai-compat-responses-head-parity.json by running these same
3
+ // captures against the pre-change (HEAD) converters.
4
+ import { sendCompatResponses } from './openai-compat-responses.mjs';
5
+ import { OpenAICompatProvider } from './openai-compat.mjs';
6
+ import { buildRequestBody } from './openai-responses-payload.mjs';
7
+ import { createProviderReplay } from './lib/provider-replay.mjs';
8
+
9
+ export const SERVER_CALL = {
10
+ type: 'tool_search_call',
11
+ id: 'ts_srv',
12
+ call_id: null,
13
+ execution: 'server',
14
+ arguments: { query: 'q' },
15
+ };
16
+ export const SERVER_OUTPUT = { type: 'tool_search_output', id: 'tso_srv', call_id: null, execution: 'server', tools: [] };
17
+ export const REPLY = { type: 'message', role: 'assistant', content: [{ type: 'output_text', text: 'ok' }] };
18
+
19
+ export const ROUTES = [
20
+ ['opencode-go', 'gpt-5.5'],
21
+ ['muse-code', 'muse-spark'],
22
+ ['command-code', 'gpt-5.5'],
23
+ ['custom-cmd', 'openai/gpt-5.6-sol'],
24
+ ['openrouter', 'openai/gpt-5.5'],
25
+ ['xai', 'grok-4'],
26
+ ['opencode-go', 'grok-4'],
27
+ ];
28
+ export const FIRST_PARTY = [
29
+ ['openai', 'gpt-5.5'],
30
+ ['openai-oauth', 'gpt-5.5'],
31
+ ];
32
+
33
+ export const replayOwner = (name) => `compat-responses:${name}`;
34
+
35
+ const search = (name) => ({
36
+ provider: name,
37
+ openaiTools: [{ type: 'function', name: 'x', description: 'd', parameters: { type: 'object', properties: {} } }],
38
+ });
39
+
40
+ export function nativeHistory() {
41
+ return [
42
+ { role: 'user', content: 'go' },
43
+ {
44
+ role: 'assistant',
45
+ content: '',
46
+ toolCalls: [
47
+ { id: 'ts1', name: 'load_tool', arguments: { names: ['x'] }, nativeType: 'tool_search_call' },
48
+ { id: 'cu1', name: 'apply_patch', arguments: { patch: 'P' }, nativeType: 'custom_tool_call' },
49
+ { id: 'fn1', name: 'Read', arguments: { path: 'a' } },
50
+ ],
51
+ },
52
+ { role: 'tool', toolCallId: 'ts1', content: 'loaded' },
53
+ { role: 'tool', toolCallId: 'cu1', content: 'patched' },
54
+ { role: 'tool', toolCallId: 'fn1', content: 'file' },
55
+ { role: 'user', content: 'next' },
56
+ ];
57
+ }
58
+
59
+ // Left by a previous openai-oauth route: native search/custom calls, native
60
+ // search results carrying loaded tools, phase-tagged assistant turns, a Skill
61
+ // result with loadable tools, and a foreign openai-responses replay.
62
+ export function oauthHistory() {
63
+ return [
64
+ { role: 'system', content: 'sys' },
65
+ { role: 'user', content: 'go' },
66
+ { role: 'assistant', content: 'working', phase: 'commentary', toolCalls: [] },
67
+ {
68
+ role: 'assistant',
69
+ content: 'looking',
70
+ phase: 'commentary',
71
+ reasoningItems: [{ id: 'rs', encrypted_content: 'ENC', summary: [] }],
72
+ toolCalls: [
73
+ { id: 'ts1', name: 'load_tool', arguments: { names: ['x'] }, nativeType: 'tool_search_call' },
74
+ { id: 'cu1', name: 'apply_patch', arguments: { patch: 'P' }, nativeType: 'custom_tool_call' },
75
+ { id: 'sk1', name: 'Skill', arguments: { name: 's' } },
76
+ ],
77
+ },
78
+ { role: 'tool', toolCallId: 'ts1', content: 'loaded', nativeToolSearch: search('openai-oauth') },
79
+ { role: 'tool', toolCallId: 'cu1', content: 'patched' },
80
+ { role: 'tool', toolCallId: 'sk1', content: 'skill', nativeToolSearch: search('openai-oauth') },
81
+ {
82
+ role: 'assistant',
83
+ content: '',
84
+ toolCalls: [{ id: 'f2', name: 'Read', arguments: { path: 'a' } }],
85
+ providerReplay: createProviderReplay('openai-responses', [
86
+ { type: 'tool_search_call', call_id: 'ts9', execution: 'client', arguments: {} },
87
+ ]),
88
+ },
89
+ { role: 'tool', toolCallId: 'f2', content: 'file' },
90
+ { role: 'user', content: 'next' },
91
+ ];
92
+ }
93
+
94
+ // Same-owner replay envelope holding a server-executed search pair.
95
+ export function serverSearchReplayHistory(owner) {
96
+ return [
97
+ { role: 'user', content: 'find tools' },
98
+ {
99
+ role: 'assistant',
100
+ content: 'done',
101
+ providerReplay: createProviderReplay(owner, [
102
+ { type: 'reasoning', id: 'rs_1', encrypted_content: 'ENC', summary: [] },
103
+ SERVER_CALL,
104
+ SERVER_OUTPUT,
105
+ { type: 'function_call', call_id: 'c1', name: 'Read', arguments: '{}' },
106
+ ]),
107
+ toolCalls: [{ id: 'c1', name: 'Read', arguments: {} }],
108
+ },
109
+ { role: 'tool', toolCallId: 'c1', content: 'ok' },
110
+ { role: 'user', content: 'next' },
111
+ ];
112
+ }
113
+
114
+ // Pre-change flag-off cases: [label, history(name), providerState?]
115
+ export const COMPAT_CASES = [
116
+ ['native', () => nativeHistory()],
117
+ ['oauth', () => oauthHistory()],
118
+ ['own-search-output', (name) => {
119
+ const h = nativeHistory();
120
+ h[2] = { ...h[2], nativeToolSearch: search(name) };
121
+ return h;
122
+ }],
123
+ ['server-replay', (name, owner = replayOwner(name)) => serverSearchReplayHistory(owner)],
124
+ ];
125
+
126
+ export function compatProvider(name, config = {}) {
127
+ const requests = [];
128
+ const provider = Object.assign(Object.create(OpenAICompatProvider.prototype), {
129
+ name,
130
+ config: { preconnect: false, ...config },
131
+ nativePdf: true,
132
+ client: {
133
+ responses: {
134
+ create: async (params) => {
135
+ requests.push(structuredClone(params));
136
+ return (async function* () {
137
+ yield {
138
+ type: 'response.completed',
139
+ response: { id: 'resp-1', model: params.model, status: 'completed', output: [REPLY] },
140
+ };
141
+ })();
142
+ },
143
+ },
144
+ },
145
+ });
146
+ return { provider, requests };
147
+ }
148
+
149
+ export async function captureCompat(name, model, history, opts = {}, config = {}) {
150
+ const { provider, requests } = compatProvider(name, config);
151
+ await sendCompatResponses(provider, history, model, [], { sessionId: 'sess-1', ...opts });
152
+ return requests[0];
153
+ }
154
+
155
+ export function captureFirstParty(name, model, history) {
156
+ return JSON.parse(JSON.stringify(buildRequestBody(history, model, [], { promptCacheProvider: name, sessionId: 'sess-1' })));
157
+ }
158
+
159
+ export async function captureAll() {
160
+ const out = {};
161
+ for (const [name, model] of ROUTES) {
162
+ for (const [label, build] of COMPAT_CASES) {
163
+ out[`compat/${name}/${model}/${label}`] = await captureCompat(name, model, build(name));
164
+ }
165
+ }
166
+ for (const [name, model] of FIRST_PARTY) {
167
+ for (const [label, build] of COMPAT_CASES) {
168
+ out[`first-party/${name}/${label}`] = captureFirstParty(name, model, build(name, 'openai-responses'));
169
+ }
170
+ }
171
+ return out;
172
+ }
@@ -139,11 +139,11 @@ export function createResponsesOutcomeStamper(state, leakedCalls) {
139
139
  }
140
140
 
141
141
  /** A streamed function_call whose id/name never arrived cannot be dispatched. */
142
- export function unresolvedSalvageError(state) {
142
+ export function unresolvedSalvageError(state, label) {
143
143
  const unresolved = state.toolCalls.find((t) => t._pendingItemId);
144
144
  if (!unresolved) return null;
145
145
  return new Error(
146
- `xAI Responses stream function_call salvage failed: missing call_id/name for item_id=${unresolved._pendingItemId || '?'}`
146
+ `${label || 'compat Responses'} stream function_call salvage failed: missing call_id/name for item_id=${unresolved._pendingItemId || '?'}`
147
147
  );
148
148
  }
149
149
 
@@ -169,5 +169,6 @@ export function finalizeResponsesStream(state, { leakedCalls, parseResponsesTool
169
169
  model: state.model || response.model || null,
170
170
  responseId: state.responseId || response.id || null,
171
171
  stopReason: state.stopReason || null,
172
+ reasoningEmitted: state.emittedReasoning === true,
172
173
  };
173
174
  }
@@ -7,6 +7,7 @@
7
7
  // turn tool loops keep the model's reasoning chain without server storage.
8
8
 
9
9
  import { markProviderRecoveryExhausted, withRetry } from './retry-classifier.mjs';
10
+ import { compatRetryOptions, withCompatRetryProfile } from './openai-compat-retry-profile.mjs';
10
11
  import { consumeCompatResponsesStream } from './openai-compat-stream.mjs';
11
12
  import { getModelMetadataSync } from './model-catalog.mjs';
12
13
  import { PROVIDER_FIRST_BYTE_TIMEOUT_MS, createPassthroughSignal } from '../stall-policy.mjs';
@@ -21,9 +22,12 @@ import {
21
22
  toXaiResponsesInput,
22
23
  xaiSystemInstructions,
23
24
  } from './openai-compat-wire.mjs';
25
+ import { nativeDeferredFamilyForRoute } from './wire-route.mjs';
24
26
  import { preparePdfTextForProvider } from './media-normalization.mjs';
25
27
  import { normalizeOpencodeGoReasoningEffort } from './openai-compat-xai.mjs';
26
28
  import { isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
29
+ import { projectEffortConfiguration, withEffortConfigurationFallback } from './effort-configuration.mjs';
30
+ import { normalizeCacheKey } from '../agent-runtime/cache-strategy.mjs';
27
31
  import { createProviderReplay } from './lib/provider-replay.mjs';
28
32
  import {
29
33
  applyCompatToolChoice,
@@ -53,9 +57,88 @@ function resolveReasoning(provider, useModel, opts) {
53
57
  return reasoningEffort ? { effort: reasoningEffort } : null;
54
58
  }
55
59
 
60
+ /**
61
+ * A custom route's mid-conversation effort projection (GPT-6+ on this wire)
62
+ * with every effort in the row's wire value, or null for the per-request
63
+ * effort. Consecutive efforts sharing one wire value collapse into none; an
64
+ * effort the row cannot serve falls back to the per-request effort.
65
+ */
66
+ function customEffortProjection(provider, useModel, messages, opts) {
67
+ if (!isCustomProviderName(provider.name)) return null;
68
+ const projection = projectEffortConfiguration(messages, provider.name, useModel, {
69
+ ...opts,
70
+ protocol: 'openai-responses',
71
+ });
72
+ if (!projection) return null;
73
+ const model = provider.getCachedModelInfo?.(useModel) || null;
74
+ const wire = (effort) =>
75
+ resolveCustomReasoning({ protocol: 'openai-responses', model, effort }).fields.reasoning?.effort || null;
76
+ const initialEffort = wire(projection.initialEffort);
77
+ if (!initialEffort) return null;
78
+ const updates = new Map();
79
+ let current = initialEffort;
80
+ for (const [message, effort] of projection.updates) {
81
+ const value = wire(effort);
82
+ if (!value) return null;
83
+ if (value !== current) {
84
+ current = value;
85
+ updates.set(message, value);
86
+ }
87
+ }
88
+ return { ...projection, initialEffort, effort: current, updates };
89
+ }
90
+
91
+ // Whether the endpoint takes `prompt_cache_key`. An explicit
92
+ // `opts.responsesPromptCacheKey` / `config.responsesPromptCacheKey` boolean
93
+ // decides; otherwise only custom routes (which always had it) send it.
94
+ function supportsPromptCacheKey(provider, opts) {
95
+ const declared = opts.responsesPromptCacheKey ?? provider.config?.responsesPromptCacheKey;
96
+ return typeof declared === 'boolean' ? declared : isCustomProviderName(provider.name);
97
+ }
98
+
99
+ // Native Responses items (tool_search_call/output, custom_tool_call/output) in
100
+ // replayed history are strictly opt-in: only a route that declares
101
+ // `responsesNativeItems: true` (opts or config) gets the first-party lowering.
102
+ // Every other route keeps the function-only lowering byte for byte.
103
+ function supportsNativeResponsesItems(provider, opts) {
104
+ return (opts.responsesNativeItems ?? provider.config?.responsesNativeItems) === true || hasNativeDeferredTools(provider, opts);
105
+ }
106
+
107
+ // A session whose pinned route verified native deferred tools on the Responses
108
+ // wire (flag off in every PROFILES entry today): tool_search is declared
109
+ // natively and loaded tools replay as tool_search_output.
110
+ function hasNativeDeferredTools(provider, opts) {
111
+ return nativeDeferredFamilyForRoute(provider.name, opts.wireRoute ?? opts.session?.wireRoute) === 'openai';
112
+ }
113
+
114
+ /**
115
+ * A route's session identity: its prompt_cache_key and (custom routes) session
116
+ * headers, '' without a session. The session wins over the provider-scoped
117
+ * cache key, so parallel sessions never evict each other; a one-shot role
118
+ * ('shared' scope, a fresh session per call) keys on the provider key instead.
119
+ * Never the effort, so an effort change keeps the cache routing.
120
+ */
121
+ function customSessionCacheKey(provider, opts) {
122
+ if (!supportsPromptCacheKey(provider, opts)) return '';
123
+ const explicit = opts.promptCacheKey || opts.providerCacheKey || opts.session?.promptCacheKey;
124
+ return normalizeCacheKey(
125
+ opts.promptCacheScope === 'shared' ? explicit || opts.sessionId : opts.sessionId || explicit
126
+ );
127
+ }
128
+
56
129
  /** The request body: lowered transcript plus the per-turn knobs (output cap,
57
- * tools and tool choice, reasoning effort). */
58
- function buildCompatResponsesParams({ provider, useModel, input, previousResponseId, tools, opts, instructions }) {
130
+ * tools and tool choice, reasoning effort, session cache key). */
131
+ function buildCompatResponsesParams({
132
+ provider,
133
+ useModel,
134
+ input,
135
+ previousResponseId,
136
+ tools,
137
+ opts,
138
+ instructions,
139
+ effortProjection,
140
+ sessionCacheKey,
141
+ }) {
59
142
  const params = {
60
143
  model: useModel,
61
144
  input,
@@ -67,18 +150,27 @@ function buildCompatResponsesParams({ provider, useModel, input, previousRespons
67
150
  const maxOutputTokens = resolveCompatMaxOutputTokens(opts);
68
151
  if (maxOutputTokens) params.max_output_tokens = maxOutputTokens;
69
152
  if (tools?.length) {
70
- params.tools = toResponsesTools(tools, { provider: provider.name });
153
+ params.tools = toResponsesTools(tools, {
154
+ provider: provider.name,
155
+ onToolExcluded: opts.onToolExcluded,
156
+ ...(hasNativeDeferredTools(provider, opts) ? { nativeDeferredTools: true } : {}),
157
+ });
71
158
  params.parallel_tool_calls = true;
72
159
  }
73
160
  applyCompatToolChoice(params, opts);
74
- const reasoning = resolveReasoning(provider, useModel, opts);
161
+ // A projected conversation keeps its initial effort on top; changes ride as input items.
162
+ const reasoning = effortProjection
163
+ ? { effort: effortProjection.initialEffort }
164
+ : resolveReasoning(provider, useModel, opts);
75
165
  if (reasoning) params.reasoning = reasoning;
76
166
  // Opt-in system-as-instructions: set before the hook so the hook can override it.
77
167
  if (instructions) params.instructions = instructions;
168
+ if (sessionCacheKey) params.prompt_cache_key = sessionCacheKey;
78
169
  // Opt-in per-provider final shaping (a provider passes the hook in its config).
79
170
  const hook = provider.config?.responsesParamsHook;
80
171
  if (typeof hook === 'function') {
81
- const modelInfo = (typeof provider.getCachedModelInfo === 'function' && provider.getCachedModelInfo(useModel)) || null;
172
+ const modelInfo =
173
+ (typeof provider.getCachedModelInfo === 'function' && provider.getCachedModelInfo(useModel)) || null;
82
174
  hook(params, { useModel, opts, modelInfo });
83
175
  }
84
176
  return params;
@@ -90,16 +182,16 @@ function buildCompatResponsesParams({ provider, useModel, input, previousRespons
90
182
  * that re-opens the request. A content-idle stall is terminal for this
91
183
  * transport, so it is marked recovery-exhausted rather than retried.
92
184
  */
93
- async function streamCompatResponses({ provider, params, label, signal, opts }) {
185
+ async function streamCompatResponses({ provider, params, label, signal, opts, headers }) {
94
186
  const totalSignal = createPassthroughSignal(signal);
95
187
  try {
96
188
  return await withRetry(
97
- async ({ signal: attemptSignal }) => {
189
+ withCompatRetryProfile(provider.name, async ({ signal: attemptSignal }) => {
98
190
  const stream = await withRetry(
99
191
  ({ signal: openSignal }) =>
100
192
  provider.client.responses.create(params, {
101
193
  signal: openSignal,
102
- ...(opts.requestHeaders ? { headers: opts.requestHeaders } : {}),
194
+ ...(headers ? { headers } : {}),
103
195
  }),
104
196
  {
105
197
  signal: attemptSignal,
@@ -130,11 +222,12 @@ async function streamCompatResponses({ provider, params, label, signal, opts })
130
222
  }
131
223
  throw error;
132
224
  }
133
- },
225
+ }),
134
226
  {
135
227
  signal: totalSignal.signal,
136
228
  onRetry: compatStreamRetryReporter(label, opts),
137
229
  retry529: opts.retry529,
230
+ ...compatRetryOptions(provider.name),
138
231
  }
139
232
  );
140
233
  } finally {
@@ -142,12 +235,36 @@ async function streamCompatResponses({ provider, params, label, signal, opts })
142
235
  }
143
236
  }
144
237
 
238
+ // OpenRouter's Responses endpoint is stateless: it does not store responses or
239
+ // resolve `previous_response_id`. Imported server-side continuation state (a
240
+ // previous id, or a stored response) is rejected up front rather than sent.
241
+ function assertOpenRouterStateless(provider, opts) {
242
+ if (provider.name !== 'openrouter') return;
243
+ const imported = opts.providerState?.[COMPAT_RESPONSES_STATE_KEY];
244
+ const previous = typeof imported?.previousResponseId === 'string' && imported.previousResponseId !== '';
245
+ if (!previous && imported?.store !== true) return;
246
+ throw Object.assign(
247
+ new Error(
248
+ 'openrouter Responses is stateless: imported previous_response_id / store:true continuation state is not supported'
249
+ ),
250
+ { code: 'OPENROUTER_RESPONSES_STATELESS_ONLY', provider: provider.name }
251
+ );
252
+ }
253
+
145
254
  /**
146
255
  * Send one turn over `POST {baseURL}/responses` (streaming) using the
147
256
  * provider's existing OpenAI SDK client. Returns the same result shape as
148
- * the chat/completions path so the agent loop stays wire-agnostic.
257
+ * the chat/completions path so the agent loop stays wire-agnostic. A custom
258
+ * route whose model rejects the mid-conversation effort update is replayed
259
+ * once with the per-request effort.
149
260
  */
150
- export async function sendCompatResponses(provider, messages, useModel, tools, opts = {}) {
261
+ export function sendCompatResponses(provider, messages, useModel, tools, opts = {}) {
262
+ const send = (sendOpts) => sendCompatResponsesOnce(provider, messages, useModel, tools, sendOpts);
263
+ if (!isCustomProviderName(provider.name)) return send(opts);
264
+ return withEffortConfigurationFallback(provider.name, useModel, opts, send);
265
+ }
266
+
267
+ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts) {
151
268
  const replayProvider = compatResponsesReplayProvider(provider.name);
152
269
  const signal = opts.signal || null;
153
270
  if (signal?.aborted) {
@@ -156,17 +273,21 @@ export async function sendCompatResponses(provider, messages, useModel, tools, o
156
273
  }
157
274
  const label = `${provider.name}:responses`;
158
275
  messages = await preparePdfTextForProvider(messages, provider);
276
+ assertOpenRouterStateless(provider, opts);
277
+ const effortProjection = customEffortProjection(provider, useModel, messages, opts);
278
+ const sessionCacheKey = customSessionCacheKey(provider, opts);
159
279
  const { input, previousResponseId, continuationResetReason } = toXaiResponsesInput(messages, opts.providerState, {
280
+ effortProjection,
160
281
  model: useModel,
161
282
  stateKey: COMPAT_RESPONSES_STATE_KEY,
162
283
  replayProvider,
163
284
  providerName: provider.name,
285
+ nativeLowering: supportsNativeResponsesItems(provider, opts),
164
286
  nativePdf: provider.nativePdf,
165
287
  // Opt-in: system prompts travel as top-level `instructions`, not input items.
166
288
  includeSystem: provider.config?.responsesSystemAsInstructions !== true,
167
289
  });
168
- const instructions =
169
- provider.config?.responsesSystemAsInstructions === true ? xaiSystemInstructions(messages) : '';
290
+ const instructions = provider.config?.responsesSystemAsInstructions === true ? xaiSystemInstructions(messages) : '';
170
291
  const params = buildCompatResponsesParams({
171
292
  provider,
172
293
  useModel,
@@ -175,14 +296,20 @@ export async function sendCompatResponses(provider, messages, useModel, tools, o
175
296
  tools,
176
297
  opts,
177
298
  instructions,
299
+ effortProjection,
300
+ sessionCacheKey,
178
301
  });
302
+ // The session identity also travels as headers; caller headers win.
303
+ const headers = sessionCacheKey && isCustomProviderName(provider.name)
304
+ ? { 'session-id': sessionCacheKey, 'x-client-request-id': sessionCacheKey, ...opts.requestHeaders }
305
+ : opts.requestHeaders;
179
306
 
180
307
  try {
181
308
  opts.onStageChange?.('requesting');
182
309
  } catch {
183
310
  /* heartbeat best-effort */
184
311
  }
185
- const streamed = await streamCompatResponses({ provider, params, label, signal, opts });
312
+ const streamed = await streamCompatResponses({ provider, params, label, signal, opts, headers });
186
313
  const response = streamed.response;
187
314
  const usage = response?.usage || null;
188
315
  const inputTokens = Number(usage?.input_tokens ?? usage?.prompt_tokens ?? 0);
@@ -206,7 +333,7 @@ export async function sendCompatResponses(provider, messages, useModel, tools, o
206
333
  const messageIndex = Array.isArray(messages) ? messages.length : 0;
207
334
  const encryptedReasoningHistory = [
208
335
  ...(Array.isArray(priorState?.encryptedReasoningHistory) ? priorState.encryptedReasoningHistory : []),
209
- ...(reasoningItems.length ? [{ messageIndex, items: reasoningItems }] : []),
336
+ ...(reasoningItems.length ? [{ messageIndex, items: reasoningItems, owner: replayProvider }] : []),
210
337
  ];
211
338
  const searchSources = collectCompatResponseSearchSources(response);
212
339
  const usageSummary = usage ? responsesUsage(usage) : undefined;
@@ -215,6 +342,7 @@ export async function sendCompatResponses(provider, messages, useModel, tools, o
215
342
  model: response?.model || useModel,
216
343
  toolCalls: streamed.toolCalls,
217
344
  stopReason: streamed.stopReason || null,
345
+ ...(streamed.refusal ? { refusal: streamed.refusal } : {}),
218
346
  ...(streamed.stopReason === 'length' && (streamed.content || '').length > 0 ? { truncated: true } : {}),
219
347
  citations: searchSources.citations.length ? searchSources.citations : undefined,
220
348
  webSearchCalls: searchSources.webSearchCalls.length ? searchSources.webSearchCalls : undefined,
@@ -225,6 +353,7 @@ export async function sendCompatResponses(provider, messages, useModel, tools, o
225
353
  previousResponseId: null,
226
354
  responseId: response?.id || null,
227
355
  store: false,
356
+ owner: replayProvider,
228
357
  encryptedReasoningItems: reasoningItems,
229
358
  encryptedReasoningHistory,
230
359
  seenMessageCount: messageIndex,
@@ -0,0 +1,193 @@
1
+ // Per-provider request retry profile for the OpenAI-compatible family. Each
2
+ // provider carries its own retry constants; the
3
+ // shared withRetry still owns classification, the exposure/replay veto,
4
+ // quota refusals, x-should-retry and Retry-After. Providers with no profile
5
+ // keep the shared defaults.
6
+ //
7
+ // `backoffMs[n]` is the base wait before retry n (index 0 is never read, so
8
+ // the first value is the duplicate the withRetry schedule expects).
9
+ // statusRetryCaps — retries allowed for one status (for example a
10
+ // 429 stops after a single retry, whatever the overall budget).
11
+ // terminalStatuses — statuses that are terminal although the
12
+ // shared classifier would retry them.
13
+ // retryOnlyStatuses — the complete retryable error set: any other 4xx/5xx
14
+ // status surfaces.
15
+ // maxRetryAfterMs — give up instead of waiting longer than this.
16
+ // maxFailedAttemptMs — a 5xx that took longer than this is not replayed.
17
+ // retryEmptyResponse — a completed turn with no text, tool call or
18
+ // reasoning is re-asked inside the ladder (nothing was exposed); a number
19
+ // bounds how many times per send, true leaves it to the ladder.
20
+ // adviceWindow - outside exceptStatuses, Retry-After is clamped to maxMs
21
+ // and jittered by jitterRatio (the advice of the excepted statuses stays raw).
22
+ // recycleDispatcherOn5xx — a retried 5xx rebuilds the shared HTTP pool.
23
+ // adviceAtLeastBackoff — the advice is a floor under the jittered backoff step.
24
+ // Every stop is provider-terminal: the profile's limits are final, so the
25
+ // agent loop never re-runs a stopped or exhausted request (see
26
+ // COMPAT_RETRY_POLICY).
27
+ import { markProviderRecoveryExhausted } from './retry-classifier.mjs';
28
+ import { retryAfterMsFromError } from './provider-error-kind.mjs';
29
+ import { STREAM_TRANSPORTS, stampStreamOutcome } from './lib/stream-outcome.mjs';
30
+ import { jitterDelayMs } from './retry-backoff.mjs';
31
+
32
+ const statusOf = (err) => Number(err?.httpStatus || err?.status || err?.response?.status || 0);
33
+
34
+ /** Loop retry policy of every profiled provider: no recovery cycles on top of the profile. */
35
+ export const COMPAT_RETRY_POLICY = Object.freeze({ recoveryCycles: false });
36
+
37
+ /** xAI additionally treats an in-band invalid-request error as retryable. */
38
+ export const XAI_COMPAT_RETRY_POLICY = Object.freeze({ ...COMPAT_RETRY_POLICY, inBandInvalidRequestRetryable: true });
39
+
40
+ export const COMPAT_RETRY_PROFILES = Object.freeze({
41
+ // A budget of 15 sends (the retry limit is reached when the next retry number
42
+ // equals it, so 14 waits), 2s doubling to 30s, ±20% jitter, one retry for a
43
+ // 429. Outside a 429, Retry-After is capped at 30s and jittered.
44
+ xai: Object.freeze({
45
+ maxAttempts: 15,
46
+ backoffMs: [2000, 2000, 4000, 8000, 16000, 30000],
47
+ retryJitterRatio: 0.2,
48
+ statusRetryCaps: { 429: 1 },
49
+ terminalStatuses: [408, 409, 425],
50
+ retryEmptyResponse: true,
51
+ adviceWindow: Object.freeze({ maxMs: 30_000, jitterRatio: 0.2, exceptStatuses: [429] }),
52
+ recycleDispatcherOn5xx: true,
53
+ }),
54
+ // 5 retries, 500ms doubling to 10s, ±10% jitter;
55
+ // a Retry-After beyond the 10s ceiling is not waited out.
56
+ deepseek: Object.freeze({
57
+ maxAttempts: 6,
58
+ backoffMs: [500, 500, 1000, 2000, 4000, 8000],
59
+ retryJitterRatio: 0.1,
60
+ maxRetryAfterMs: 10_000,
61
+ terminalStatuses: [408, 409, 425],
62
+ retryEmptyResponse: true,
63
+ }),
64
+ // The HTTP transport layer governs one request: 6 sends, 500ms doubling, no
65
+ // jitter, a Retry-After beyond 60s is not waited out; only 408, 429 and 5xx
66
+ // are transient, every other 4xx is terminal. A benign empty completion is
67
+ // re-asked at most twice.
68
+ 'muse-code-oauth': Object.freeze({
69
+ maxAttempts: 6,
70
+ backoffMs: [500, 500, 1000, 2000, 4000, 8000],
71
+ retryJitterRatio: 0,
72
+ terminalStatuses: [409, 425],
73
+ maxRetryAfterMs: 60_000,
74
+ retryEmptyResponse: 2,
75
+ }),
76
+ // server budget 8 retries (2s doubling to 30s,
77
+ // ±10%), rate-limit budget 5 retries; 408, 409, 501 and 505 are terminal
78
+ // (425 stays retryable); a Retry-After beyond 300s is not waited out.
79
+ 'mimo-oauth': Object.freeze({
80
+ maxAttempts: 9,
81
+ backoffMs: [2000, 2000, 4000, 8000, 16000, 30000],
82
+ retryJitterRatio: 0.1,
83
+ statusRetryCaps: { 429: 5 },
84
+ terminalStatuses: [408, 409, 501, 505],
85
+ maxRetryAfterMs: 300_000,
86
+ }),
87
+ // 3 sends (400ms doubling to 5s) for exactly
88
+ // 500/502/503/504/520/521/522 — every 4xx (429 included) and every other
89
+ // 5xx is terminal; a failed attempt slower than 15s is returned.
90
+ 'command-code-oauth': Object.freeze({
91
+ maxAttempts: 3,
92
+ backoffMs: [400, 400, 800],
93
+ retryOnlyStatuses: [500, 502, 503, 504, 520, 521, 522],
94
+ maxFailedAttemptMs: 15_000,
95
+ maxRetryAfterMs: 60_000,
96
+ adviceAtLeastBackoff: true,
97
+ }),
98
+ });
99
+
100
+ /** withRetry options (attempt budget, schedule, jitter) for a provider; {} for the shared defaults. */
101
+ export function compatRetryOptions(providerName) {
102
+ const profile = COMPAT_RETRY_PROFILES[providerName];
103
+ if (!profile) return {};
104
+ return {
105
+ maxAttempts: profile.maxAttempts,
106
+ backoffMs: profile.backoffMs,
107
+ retryJitterRatio: profile.retryJitterRatio,
108
+ finalOnExhaust: true,
109
+ ...(profile.adviceAtLeastBackoff ? { adviceAtLeastBackoff: true } : {}),
110
+ ...(profile.recycleDispatcherOn5xx ? { recycleDispatcherOn5xx: true } : {}),
111
+ ...(profile.retryJitterMode ? { retryJitterMode: profile.retryJitterMode } : {}),
112
+ };
113
+ }
114
+
115
+ function profileStops(profile, err, { attempt, elapsedMs }) {
116
+ const status = statusOf(err);
117
+ if (profile.terminalStatuses?.includes(status)) return true;
118
+ const cap = profile.statusRetryCaps?.[status];
119
+ if (cap !== undefined && attempt >= cap) return true;
120
+ if (profile.retryOnlyStatuses && status >= 400 && status < 600 && !profile.retryOnlyStatuses.includes(status)) {
121
+ return true;
122
+ }
123
+ if (profile.maxFailedAttemptMs && status >= 500 && status < 600 && elapsedMs > profile.maxFailedAttemptMs) {
124
+ return true;
125
+ }
126
+ const advice = retryAfterMsFromError(err);
127
+ return profile.maxRetryAfterMs !== undefined && advice != null && advice > profile.maxRetryAfterMs;
128
+ }
129
+
130
+ // Restamps the advice as a deadline (the highest-precedence source) so the
131
+ // shared loop waits the clamped, jittered value instead of the raw one.
132
+ function shapeAdvice(window, err) {
133
+ if (!window || !err || typeof err !== 'object' || window.exceptStatuses?.includes(statusOf(err))) return;
134
+ const advice = retryAfterMsFromError(err);
135
+ if (advice == null) return;
136
+ err.retryAfterAt = Date.now() + jitterDelayMs(Math.min(advice, window.maxMs), window.jitterRatio);
137
+ }
138
+
139
+ // A completed turn that produced nothing: no text, tool call or reasoning, and
140
+ // a normal finish (a Responses turn carries no stop reason when it completes).
141
+ function isEmptyNormalFinish(result) {
142
+ if (!result || typeof result !== 'object') return false;
143
+ if (result.stopReason != null && result.stopReason !== 'stop') return false;
144
+ return (
145
+ !String(result.content ?? '').trim() &&
146
+ !result.toolCalls?.length &&
147
+ !result.reasoningContent &&
148
+ !result.reasoningDetails?.length &&
149
+ result.reasoningEmitted !== true
150
+ );
151
+ }
152
+
153
+ function emptyResponseError(providerName) {
154
+ const err = Object.assign(new Error(`${providerName} returned an empty response`), {
155
+ code: 'server_error',
156
+ emptyResponse: true,
157
+ });
158
+ // The turn finished: a failed ladder must not reopen it as a non-streaming request.
159
+ stampStreamOutcome(err, { transport: STREAM_TRANSPORTS.SSE, terminalObserved: true });
160
+ return err;
161
+ }
162
+
163
+ /**
164
+ * Wrap one withRetry attempt with the provider's profile: a failure the
165
+ * profile treats as final is marked recovery-exhausted and provider-terminal
166
+ * (withRetry then surfaces it unchanged and no outer layer replays it), and a
167
+ * profiled empty response is raised as a retryable failure.
168
+ */
169
+ export function withCompatRetryProfile(providerName, attemptFn) {
170
+ const profile = COMPAT_RETRY_PROFILES[providerName];
171
+ if (!profile) return attemptFn;
172
+ let emptyRetries = 0;
173
+ return async (ctx) => {
174
+ const startedAt = Date.now();
175
+ try {
176
+ const result = await attemptFn(ctx);
177
+ if (profile.retryEmptyResponse && isEmptyNormalFinish(result)) {
178
+ const bound = profile.retryEmptyResponse === true ? Infinity : profile.retryEmptyResponse;
179
+ if (emptyRetries < bound) {
180
+ emptyRetries += 1;
181
+ throw emptyResponseError(providerName);
182
+ }
183
+ }
184
+ return result;
185
+ } catch (err) {
186
+ if (profileStops(profile, err, { attempt: ctx?.attempt | 0, elapsedMs: Date.now() - startedAt })) {
187
+ throw markProviderRecoveryExhausted(err, { owner: `${providerName}-retry-profile`, terminal: true });
188
+ }
189
+ shapeAdvice(profile.adviceWindow, err);
190
+ throw err;
191
+ }
192
+ };
193
+ }