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,9 @@
1
+ // OpenAI retry schedule: 200ms base, factor 2, ±10%.
2
+ // Provider-owned values; the shared retry core only takes them as options.
3
+ // CODEX_STREAM_BACKOFF_MS — indexed by the 1-based retry number
4
+ // (midstreamBackoffFor).
5
+ // CODEX_REQUEST_RETRY_BACKOFF_MS — leading duplicate for withRetry's
6
+ // sleep-before-attempt index.
7
+ export const CODEX_STREAM_BACKOFF_MS = Object.freeze([200, 400, 800, 1600, 3200]);
8
+ export const CODEX_REQUEST_RETRY_BACKOFF_MS = Object.freeze([200, ...CODEX_STREAM_BACKOFF_MS]);
9
+ export const CODEX_RETRY_JITTER_RATIO = 0.1;
@@ -279,7 +279,7 @@ function _stripResponseItemsFromHead(items, responseItems) {
279
279
  // Official OpenAI Responses WebSocket guide: response.create WS frames mirror
280
280
  // the Responses body EXCEPT the transport-only fields `stream`/`background`,
281
281
  // which the socket carries implicitly and the guide says to omit. This set is
282
- // stripped from a frame (any build shape) only when omitTransportFields is on.
282
+ // always stripped from a frame (any build shape).
283
283
  const TRANSPORT_ONLY_FRAME_FIELDS = new Set(['stream', 'background']);
284
284
 
285
285
  // Canonical response.create frame builder. Every WS send (main full-frame
@@ -293,14 +293,12 @@ const TRANSPORT_ONLY_FRAME_FIELDS = new Set(['stream', 'background']);
293
293
  // response, so dropping them here strips the system/lead prompt from every
294
294
  // continuation turn. Only an empty instructions string is omitted.
295
295
  // Full frames pass the body unchanged and keep every key in place.
296
- // omitTransportFields is used by wire-parity helpers to drop stream/background.
297
296
  export function _buildResponseCreateFrame(
298
297
  body,
299
- { previousResponseId = null, inputOverride, omitTransportFields = false } = {}
298
+ { previousResponseId = null, inputOverride } = {}
300
299
  ) {
301
300
  const src = body && typeof body === 'object' ? body : {};
302
301
  if (previousResponseId == null && inputOverride === undefined) {
303
- if (!omitTransportFields) return { type: 'response.create', ...src };
304
302
  const frame = { type: 'response.create' };
305
303
  for (const key of Object.keys(src)) {
306
304
  if (TRANSPORT_ONLY_FRAME_FIELDS.has(key)) continue;
@@ -310,7 +308,7 @@ export function _buildResponseCreateFrame(
310
308
  }
311
309
  const frame = { type: 'response.create' };
312
310
  for (const key of Object.keys(src)) {
313
- if (omitTransportFields && TRANSPORT_ONLY_FRAME_FIELDS.has(key)) continue;
311
+ if (TRANSPORT_ONLY_FRAME_FIELDS.has(key)) continue;
314
312
  if (key === 'instructions') {
315
313
  const instr = src.instructions;
316
314
  if (typeof instr === 'string' && instr.length) frame.instructions = instr;
@@ -366,17 +364,10 @@ export function _computeDelta({ entry, body, traceProvider }) {
366
364
  if (!entry?.lastRequestSansInput || !entry.lastResponseId) {
367
365
  return { mode: 'full', reason: 'no_anchor', frame: buildFrame(body) };
368
366
  }
369
- // Public OpenAI resolves previous_response_id out of its response STORE, so
370
- // an anchor only exists when the anchored response was stored. store:false
371
- // there — e.g. an explicit MIXDOG_OAI_STORE=0 opt-out on the openai-direct
372
- // provider — makes a continuation frame fail with
373
- // previous_response_not_found, so the opt-out degrades to full frames.
374
- // openai-oauth/Codex (per-WS-session server state) and xAI (in-connection
375
- // ZDR continuation with encrypted reasoning) both anchor without the store
376
- // and are deliberately excluded from this gate.
377
- if (traceProvider === 'openai-direct' && body?.store !== true) {
378
- return { mode: 'full', reason: 'store_disabled', frame: buildFrame(body) };
379
- }
367
+ // WebSocket mode keeps the latest response in a connection-local cache, so
368
+ // previous_response_id continues on the same socket even with store:false.
369
+ // If the server no longer has the anchor (previous_response_not_found), the
370
+ // caller recovers with a full-context frame.
380
371
  if (!deltaForce && !deltaRefs && !entry.turnState) {
381
372
  return { mode: 'full', reason: 'delta_missing_turn_state', frame: buildFrame(body) };
382
373
  }
@@ -9,6 +9,11 @@
9
9
  import { appendFileSync, chmodSync } from 'node:fs';
10
10
  import { errText } from '../../../shared/err-text.mjs';
11
11
  import { _cfCookieCapture, _formatRedactedHeaders } from './openai-ws-headers.mjs';
12
+ import { httpResponseError } from './openai-error-contract.mjs';
13
+
14
+ // Enough of the handshake body to parse a typed JSON error; diagnostics are
15
+ // truncated separately by the error message.
16
+ const HANDSHAKE_BODY_LIMIT = 16 * 1024;
12
17
 
13
18
  /** CF cookie jar refresh plus the opt-in upgrade-header dump. */
14
19
  export function captureHandshakeUpgrade(auth, res) {
@@ -85,7 +90,7 @@ export function attachHandshakeFailureHandlers({ socket, errLabel, openStart, is
85
90
  const status = res?.statusCode || 0;
86
91
  let body = '';
87
92
  res.on('data', (c) => {
88
- if (body.length < 2048) body += c.toString('utf-8');
93
+ if (body.length < HANDSHAKE_BODY_LIMIT) body += c.toString('utf-8');
89
94
  });
90
95
  res.on('end', () => {
91
96
  if (process.env.MIXDOG_DEBUG_AGENT) {
@@ -96,13 +101,16 @@ export function attachHandshakeFailureHandlers({ socket, errLabel, openStart, is
96
101
  try {
97
102
  socket.terminate();
98
103
  } catch {}
99
- settle(
100
- false,
101
- Object.assign(new Error(`${errLabel} handshake ${status}: ${body.slice(0, 200)}`), {
102
- httpStatus: status,
103
- httpBody: body,
104
- })
105
- );
104
+ // Status, headers and the parsed body ride on the error; only the
105
+ // message is truncated.
106
+ const err = httpResponseError({
107
+ label: `${errLabel} handshake`,
108
+ status,
109
+ headers: res.headers,
110
+ text: body,
111
+ });
112
+ err.httpBody = body;
113
+ settle(false, err);
106
114
  });
107
115
  });
108
116
  }
@@ -0,0 +1,60 @@
1
+ // Refusal content of one Responses stream. The model's refusal arrives as
2
+ // `response.refusal.delta` / `response.refusal.done` and as a
3
+ // `{type:'refusal', refusal}` content part of the message item
4
+ // (output_item.done and the terminal output bundle). Parts are keyed by item
5
+ // id + content index so the streamed, item-done and terminal copies of one
6
+ // part fold into one text; a full (done / final-part) text replaces the
7
+ // accumulated deltas. Shared by the WS and HTTP/SSE collectors.
8
+ export function createRefusals() {
9
+ const parts = new Map();
10
+ const keyOf = (itemId, contentIndex) => `${itemId || ''}:${Number.isInteger(contentIndex) ? contentIndex : 0}`;
11
+
12
+ return {
13
+ /** response.refusal.delta */
14
+ delta(event) {
15
+ if (typeof event?.delta !== 'string') return;
16
+ const key = keyOf(event.item_id, event.content_index);
17
+ parts.set(key, (parts.get(key) || '') + event.delta);
18
+ },
19
+ /** response.refusal.done */
20
+ done(event) {
21
+ if (typeof event?.refusal !== 'string') return;
22
+ parts.set(keyOf(event.item_id, event.content_index), event.refusal);
23
+ },
24
+ /** A message item's refusal parts. Returns whether it carried any. */
25
+ absorbMessage(item) {
26
+ if (item?.type !== 'message' || !Array.isArray(item.content)) return false;
27
+ let found = false;
28
+ item.content.forEach((part, index) => {
29
+ if (part?.type !== 'refusal' || typeof part.refusal !== 'string') return;
30
+ found = true;
31
+ // An id-less item cannot be matched to its streamed copy; the
32
+ // streamed text already stands for it.
33
+ if (!item.id && parts.size > 0) return;
34
+ parts.set(keyOf(item.id, index), part.refusal);
35
+ });
36
+ return found;
37
+ },
38
+ get seen() {
39
+ return parts.size > 0;
40
+ },
41
+ get text() {
42
+ return [...parts.values()].filter(Boolean).join('\n');
43
+ },
44
+ };
45
+ }
46
+
47
+ /** The typed stop reason of a refused turn (read by the agent loop). */
48
+ export const REFUSAL_STOP_REASON = 'refusal';
49
+
50
+ /** Result fields for a refused turn — the shared result shape:
51
+ * stopReason: REFUSAL_STOP_REASON
52
+ * refusal: the refusal text (joined parts; may be '')
53
+ * content: the output_text, or the refusal text when there was none
54
+ * so a refusal never reads as an empty successful answer. Empty object when
55
+ * the response carried no refusal. */
56
+ export function refusalResultFields(refusals, content) {
57
+ if (!refusals.seen) return {};
58
+ const refusal = refusals.text;
59
+ return { content: content || refusal, refusal, stopReason: REFUSAL_STOP_REASON };
60
+ }
@@ -1,7 +1,12 @@
1
1
  import { makeInvalidToolArgsMarker } from '../lib/openai-tool-args.mjs';
2
2
  import { synthLeakedOpenAICall } from '../openai-compat-stream-common.mjs';
3
3
  import { createToolCallDedupe, dedupeToolCallList } from '../lib/leaked-toolcall.mjs';
4
- import { customToolCallFromResponseItem, nativeToolSearchCallFromArguments } from '../custom-tool-wire.mjs';
4
+ import {
5
+ customToolCallFromResponseItem,
6
+ nativeToolSearchCallFromArguments,
7
+ qualifiedToolCallName,
8
+ withToolCallNamespace,
9
+ } from '../custom-tool-wire.mjs';
5
10
  import { createActiveToolItemTracker } from '../tool-stream-state.mjs';
6
11
 
7
12
  // tool_search_call.arguments parse. Module-scope (exported) for direct test
@@ -64,7 +69,7 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
64
69
  } catch {}
65
70
  }
66
71
  function emit(call) {
67
- if (!toolDedupe.shouldDispatch(call?.name, call?.arguments, call?.id)) return;
72
+ if (!toolDedupe.shouldDispatch(qualifiedToolCallName(call), call?.arguments, call?.id)) return;
68
73
  fire(call);
69
74
  }
70
75
  function settle() {
@@ -84,6 +89,8 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
84
89
  }
85
90
  function pushToolSearchCall(item) {
86
91
  if (item?.type !== 'tool_search_call') return;
92
+ // Server-executed search already ran inside the response; replay-only.
93
+ if (item.execution === 'server') return;
87
94
  const callId = item.call_id || item.id || '';
88
95
  if (!callId || toolCalls.some((call) => call.id === callId)) return;
89
96
  const call = nativeToolSearchCallFromArguments(callId, parseToolSearchArgs(item.arguments));
@@ -106,7 +113,10 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
106
113
  const type = item?.type;
107
114
  if (type === 'function_call') {
108
115
  markStarted(item);
109
- pendingCalls.set(item.id || '', { name: item.name || '', callId: item.call_id || '' });
116
+ pendingCalls.set(
117
+ item.id || '',
118
+ withToolCallNamespace({ name: item.name || '', callId: item.call_id || '' }, item)
119
+ );
110
120
  } else if (type === 'custom_tool_call' || type === 'tool_search_call') {
111
121
  // tool_search is marked in-flight at item-added time too, so the
112
122
  // semantic-idle stall gate's pendingToolUse never drops a mid-flight
@@ -134,7 +144,7 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
134
144
  argumentsText: event.arguments || JSON.stringify(args),
135
145
  });
136
146
  if (pending?.callId && pending?.name) {
137
- const call = { id: pending.callId, name: pending.name, arguments: args };
147
+ const call = withToolCallNamespace({ id: pending.callId, name: pending.name, arguments: args }, pending);
138
148
  toolCalls.push(call);
139
149
  emit(call);
140
150
  pendingCalls.delete(itemId);
@@ -150,31 +160,45 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
150
160
  // bundle. If salvage also fails the stream fails explicitly — masking the
151
161
  // gap with a synthetic id just shifts the failure one turn later under a
152
162
  // confusing "No tool output found for function call" error.
153
- toolCalls.push({
154
- id: pending?.callId || '',
155
- name: pending?.name || '',
156
- arguments: args,
157
- _pendingItemId: itemId,
158
- _deferred: true,
159
- });
163
+ toolCalls.push(
164
+ withToolCallNamespace(
165
+ {
166
+ id: pending?.callId || '',
167
+ name: pending?.name || '',
168
+ arguments: args,
169
+ _pendingItemId: itemId,
170
+ _deferred: true,
171
+ },
172
+ pending
173
+ )
174
+ );
160
175
  }
161
176
 
162
- /** response.output_item.done for a function_call item */
177
+ /** A complete function_call item (output_item.done, or the terminal
178
+ * response output bundle) through the one deduplicated collector: it
179
+ * resolves the deferred placeholder for its item (canonical call_id/name
180
+ * from the item, missing ones kept from the placeholder), is skipped when
181
+ * its call_id is already recorded, and is otherwise created and
182
+ * dispatched — so a call present only in the terminal bundle still runs. */
163
183
  function completeFunctionCallItem(item) {
164
184
  const itemId = item.id || '';
165
185
  const callId = item.call_id || '';
166
186
  const name = item.name || '';
167
187
  const args = parseFunctionCallArgs(argsTextOf(item.arguments));
168
188
  const deferred = toolCalls.find((tc) => tc?._deferred && (!itemId || tc._pendingItemId === itemId));
169
- if (deferred && callId && name) {
170
- deferred.id = callId;
171
- deferred.name = name;
172
- deferred.arguments = deferred.arguments && Object.keys(deferred.arguments).length > 0 ? deferred.arguments : args;
173
- delete deferred._deferred;
174
- delete deferred._pendingItemId;
175
- emit(deferred);
189
+ if (deferred) {
190
+ deferred.id = callId || deferred.id;
191
+ deferred.name = name || deferred.name;
192
+ withToolCallNamespace(deferred, item);
193
+ if (deferred.id && deferred.name) {
194
+ deferred.arguments =
195
+ deferred.arguments && Object.keys(deferred.arguments).length > 0 ? deferred.arguments : args;
196
+ delete deferred._deferred;
197
+ delete deferred._pendingItemId;
198
+ emit(deferred);
199
+ }
176
200
  } else if (callId && name && !toolCalls.some((tc) => tc?.id === callId)) {
177
- const call = { id: callId, name, arguments: args };
201
+ const call = withToolCallNamespace({ id: callId, name, arguments: args }, item);
178
202
  toolCalls.push(call);
179
203
  emit(call);
180
204
  }
@@ -193,20 +217,6 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
193
217
  settle();
194
218
  }
195
219
 
196
- /** response.completed salvage: when arguments.done fired before (or
197
- * without) a matching output_item.added, the deferred placeholder has an
198
- * empty id/name; the bundle carries the canonical call_id/name. */
199
- function salvageFunctionCall(item) {
200
- const tc = toolCalls.find((t) => t._deferred && t._pendingItemId === (item.id || ''));
201
- if (!tc) return;
202
- if (!tc.id && item.call_id) tc.id = item.call_id;
203
- if (!tc.name && item.name) tc.name = item.name;
204
- if (tc.id && tc.name) {
205
- delete tc._deferred;
206
- delete tc._pendingItemId;
207
- emit(tc);
208
- }
209
- }
210
220
 
211
221
  return {
212
222
  get calls() {
@@ -238,6 +248,12 @@ export function createWsToolCalls({ onToolCall, midState, replayItems }) {
238
248
  completeFunctionCallItem,
239
249
  completeToolSearchItem,
240
250
  completeCustomToolItem,
241
- salvageFunctionCall,
251
+ /** A server-truncated call item: kept in flight, never collected. */
252
+ holdIncompleteItem: markStarted,
253
+ // Terminal-bundle salvage (response.completed / success response.done):
254
+ // the same collector as output_item.done. When arguments.done fired
255
+ // before (or without) output_item.added, the deferred placeholder has an
256
+ // empty id/name and the bundle carries the canonical call_id/name.
257
+ salvageFunctionCall: completeFunctionCallItem,
242
258
  };
243
259
  }
@@ -13,6 +13,8 @@ import { createReplayItems } from './openai-ws-response-state/replay-items.mjs';
13
13
  import { createCitations } from './openai-ws-response-state/citations.mjs';
14
14
  import { createWsToolCalls } from './openai-ws-response-state/tool-calls.mjs';
15
15
  import { normalizeWsUsage } from './openai-ws-response-state/usage.mjs';
16
+ import { createRefusals, refusalResultFields } from './openai-ws-response-state/refusals.mjs';
17
+ import { isIncompleteToolItem } from './lib/responses-terminal-fields.mjs';
16
18
 
17
19
  export { parseToolSearchArgs } from './openai-ws-response-state/tool-calls.mjs';
18
20
 
@@ -37,6 +39,7 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
37
39
  const reasoningDeltas = { text: 0, summary: 0, other: 0 };
38
40
  const replayItems = createReplayItems();
39
41
  const citations = createCitations();
42
+ const refusals = createRefusals();
40
43
  const tools = createWsToolCalls({ onToolCall, midState, replayItems });
41
44
  const replayProvider = traceProvider === 'xai' ? 'xai-responses' : 'openai-responses';
42
45
  const progress = (kind) => {
@@ -49,6 +52,11 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
49
52
  // anything the per-item events never carried. Returns whether any progress
50
53
  // was reported.
51
54
  function salvageCompletedItem(item, relayFinalText) {
55
+ if (isIncompleteToolItem(item)) {
56
+ tools.holdIncompleteItem(item);
57
+ progress('tool');
58
+ return true;
59
+ }
52
60
  replayItems.push(item);
53
61
  let reported = false;
54
62
  if (item.type === 'message') {
@@ -64,6 +72,10 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
64
72
  }
65
73
  citations.pushOutputTextAnnotations(c);
66
74
  }
75
+ if (refusals.absorbMessage(item)) {
76
+ progress('semantic');
77
+ reported = true;
78
+ }
67
79
  }
68
80
  if (item.type === 'web_search_call') {
69
81
  citations.pushWebSearchCall(item);
@@ -146,10 +158,19 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
146
158
  noteToolInputDelta: tools.noteToolInputDelta,
147
159
  /** response.function_call_arguments.done */
148
160
  completeFunctionCallArguments: tools.completeFunctionCallArguments,
161
+ /** response.refusal.delta */
162
+ noteRefusalDelta: refusals.delta,
163
+ /** response.refusal.done */
164
+ noteRefusalDone: refusals.done,
149
165
  /** response.output_item.done. Returns the progress kind to report. */
150
166
  completeOutputItem(item) {
167
+ if (isIncompleteToolItem(item)) {
168
+ tools.holdIncompleteItem(item);
169
+ return 'tool';
170
+ }
151
171
  replayItems.push(item);
152
172
  const type = item?.type || '';
173
+ if (type === 'message') refusals.absorbMessage(item);
153
174
  // function_call / output_text already arrive via their dedicated
154
175
  // streaming events; `reasoning` carries encrypted_content that keeps the
155
176
  // openai-oauth server-side prompt cache prefix warm.
@@ -189,6 +210,13 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
189
210
  if (!responseId && response?.id) responseId = response.id;
190
211
  return usage;
191
212
  },
213
+ /** A cutoff frame's output bundle: call items the server truncated stay
214
+ * in flight so the cutoff reads as a pending-tool turn. */
215
+ holdIncompleteBundleItems(response) {
216
+ for (const item of response?.output || []) {
217
+ if (isIncompleteToolItem(item)) tools.holdIncompleteItem(item);
218
+ }
219
+ },
192
220
  /** max_output_tokens maps cleanly to Anthropic's stop_reason=max_tokens. */
193
221
  markMaxOutputIncomplete(reason) {
194
222
  incompleteReason = reason;
@@ -227,6 +255,8 @@ export function createWsResponseState({ onToolCall, onStreamDelta, midState, tra
227
255
  ...(typeof endTurn === 'boolean' ? { endTurn } : {}),
228
256
  responseId: responseId || undefined,
229
257
  serviceTier: responseServiceTier || undefined,
258
+ // A refused turn: typed stop reason and the refusal text.
259
+ ...refusalResultFields(refusals, content),
230
260
  };
231
261
  },
232
262
  };
@@ -3,7 +3,6 @@
3
3
  * WS send, plus the surface/backoff primitives both failure resolvers use.
4
4
  */
5
5
  import { performance } from 'node:perf_hooks';
6
- import { retryAfterMsFromError } from '../retry-classifier.mjs';
7
6
  import { _sleepWithAbort, MIDSTREAM_WS_TRANSIENT_RETRY_LIMIT, midstreamBackoffFor, tag } from './policy.mjs';
8
7
 
9
8
  export function createAttemptContext(deps) {
@@ -35,7 +34,7 @@ export function createAttemptContext(deps) {
35
34
  const backoff = async (retryNumber, err = null) => {
36
35
  const sleepStart = performance.now();
37
36
  try {
38
- await _sleepWithAbort(retryAfterMsFromError(err) ?? midstreamBackoffFor(retryNumber), externalSignal, sleepFn);
37
+ await _sleepWithAbort(midstreamBackoffFor(retryNumber, err), externalSignal, sleepFn);
39
38
  } catch (sleepErr) {
40
39
  sendSpan.retryBackoffMs += performance.now() - sleepStart;
41
40
  sendSpan.emit('error');
@@ -2,12 +2,13 @@
2
2
  * policy.mjs — the WS send retry budget, its backoff curves and the
3
3
  * classification wrappers shared by the handshake and stream resolvers.
4
4
  */
5
+ import { CODEX_RETRY_JITTER_RATIO, CODEX_STREAM_BACKOFF_MS } from '../openai-retry-policy.mjs';
5
6
  import {
6
7
  classifyHandshakeError,
7
8
  classifyMidstreamError,
8
9
  isWsMessageTooBigClose,
9
- jitterDelayMs,
10
10
  MIDSTREAM_RETRY_POLICY,
11
+ midstreamBackoffFor as sharedMidstreamBackoffFor,
11
12
  sleepWithAbort,
12
13
  } from '../retry-classifier.mjs';
13
14
 
@@ -15,23 +16,26 @@ import {
15
16
  // by connect/handshake and pre-output stream failures.
16
17
  export const MIDSTREAM_WS_TRANSIENT_RETRY_LIMIT = MIDSTREAM_RETRY_POLICY.ws.transientCloseRetries;
17
18
  const MIDSTREAM_DEFAULT_RETRY_LIMIT = MIDSTREAM_RETRY_POLICY.ws.defaultRetries;
18
- // The reference client uses a 200ms base, factor 2, and symmetric ±10%
19
- // jitter for each of its five stream retries.
20
- const MIDSTREAM_BACKOFF_MS = Object.freeze([200, 400, 800, 1600, 3200]);
21
- const CODEX_RETRY_JITTER_RATIO = 0.1;
19
+ // The stream retry schedule (200ms base, factor 2, ±10%) lives in
20
+ // openai-retry-policy.mjs, shared with the HTTP request loop.
21
+ // Advice-gated retry (OAuth and API-key WS alike): an overload and an untyped 429
22
+ // retry only when the server gave advice.
23
+ const ADVICE_GATES = Object.freeze({
24
+ overloadRetryRequiresAdvice: true,
25
+ generic429RetryRequiresAdvice: true,
26
+ });
22
27
  // Policy object passed to the shared classifyMidstreamError for the WS path.
23
28
  const WS_MIDSTREAM_POLICY = {
24
29
  mode: 'ws',
25
30
  transientCloseRetries: MIDSTREAM_RETRY_POLICY.ws.transientCloseRetries,
26
31
  defaultRetries: MIDSTREAM_RETRY_POLICY.ws.defaultRetries,
32
+ ...ADVICE_GATES,
27
33
  };
28
34
 
29
35
  // Kept for the _acquireWithRetry test seam and non-Codex callers.
30
36
  // sendViaWebSocket deliberately invokes it with maxAttempts:1 so handshake
31
37
  // failures consume the same stream budget as pre-output disconnects.
32
38
  export const HANDSHAKE_MAX_ATTEMPTS = MIDSTREAM_WS_TRANSIENT_RETRY_LIMIT + 1;
33
- const HANDSHAKE_BACKOFF_BASE_MS = 200;
34
- const HANDSHAKE_BACKOFF_CAP_MS = 3200;
35
39
  // These statuses are decisions made by the CURRENT attempt. They must never
36
40
  // be replaced by a stale transient from an earlier retry: auth recovery,
37
41
  // transport fallback, and Retry-After handling all depend on the live error.
@@ -47,8 +51,15 @@ export function _mustSurfaceCurrentAttempt(err, externalSignal) {
47
51
  );
48
52
  }
49
53
 
50
- export function _classifyHandshakeError(err, { retry429 = true } = {}) {
51
- return classifyHandshakeError(err, { retry429 });
54
+ export function _classifyHandshakeError(
55
+ err,
56
+ {
57
+ retry429 = true,
58
+ overloadRetryRequiresAdvice = ADVICE_GATES.overloadRetryRequiresAdvice,
59
+ generic429RetryRequiresAdvice = ADVICE_GATES.generic429RetryRequiresAdvice,
60
+ } = {}
61
+ ) {
62
+ return classifyHandshakeError(err, { retry429, overloadRetryRequiresAdvice, generic429RetryRequiresAdvice });
52
63
  }
53
64
 
54
65
  /**
@@ -103,15 +114,15 @@ export function midstreamRetryLimit(classifier) {
103
114
  : MIDSTREAM_DEFAULT_RETRY_LIMIT;
104
115
  }
105
116
 
106
- export function midstreamBackoffFor(retryNumber) {
107
- const raw = MIDSTREAM_BACKOFF_MS[Math.min(Math.max(retryNumber, 1), MIDSTREAM_BACKOFF_MS.length) - 1];
108
- return jitterDelayMs(raw, CODEX_RETRY_JITTER_RATIO);
117
+ // Passing the failure makes server advice replace the step for retryable
118
+ // kinds only (midstreamRetryDelayMs).
119
+ export function midstreamBackoffFor(retryNumber, err = null) {
120
+ return sharedMidstreamBackoffFor(retryNumber, CODEX_STREAM_BACKOFF_MS, err, CODEX_RETRY_JITTER_RATIO);
109
121
  }
110
122
 
111
123
  export function _backoffFor(attempt) {
112
124
  // attempt is 1-based; exponential backoff is capped before jitter.
113
- const raw = HANDSHAKE_BACKOFF_BASE_MS * (1 << (attempt - 1));
114
- return jitterDelayMs(Math.min(raw, HANDSHAKE_BACKOFF_CAP_MS), CODEX_RETRY_JITTER_RATIO);
125
+ return midstreamBackoffFor(attempt);
115
126
  }
116
127
 
117
128
  export const _defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -88,6 +88,18 @@ export function createWsEventSwitch({ response, textRelay, watchdogs, midState,
88
88
  progress('tool');
89
89
  watchdogs.bumpSemantic();
90
90
  break;
91
+ // Refusal text is model output but never visible answer text: it is
92
+ // collected for the typed refusal result, not relayed live.
93
+ case 'response.refusal.delta':
94
+ response.noteRefusalDelta(event);
95
+ progress('semantic');
96
+ watchdogs.bumpSemantic();
97
+ break;
98
+ case 'response.refusal.done':
99
+ response.noteRefusalDone(event);
100
+ progress('semantic');
101
+ watchdogs.bumpSemantic();
102
+ break;
91
103
  case 'response.output_item.done': {
92
104
  const kind = response.completeOutputItem(event.item);
93
105
  // Item-done is genuine lifecycle progress — reset semantic idle so
@@ -27,11 +27,30 @@ export function createTerminalFrameHandlers({ response, textRelay, midState, err
27
27
 
28
28
  // Most incomplete reasons are real failures. max_output_tokens maps cleanly
29
29
  // to Anthropic's stop_reason=max_tokens; treating it as an error makes
30
- // Claude retry the same over-budget turn.
30
+ // Claude retry the same over-budget turn — unless a tool call's input was
31
+ // still streaming: its arguments were truncated, so the cutoff is a
32
+ // stalled pending-tool turn (same guard as HTTP/SSE), never a clean length
33
+ // completion that would surface the partial call as successful.
31
34
  function settleIncomplete(event, label, options) {
32
35
  const usage = response.noteTerminal(event.response);
33
36
  const reasonStr = _incompleteReasonFromEvent(event);
34
37
  if (_isMaxOutputIncompleteReason(reasonStr)) {
38
+ response.holdIncompleteBundleItems(event.response);
39
+ if (response.pendingToolUse) {
40
+ const error = new Error(`${label} (max_output_tokens) with tool call in flight`);
41
+ try {
42
+ textRelay.flush();
43
+ } catch {
44
+ /* best-effort */
45
+ }
46
+ Object.assign(error, response.partialState());
47
+ error.streamStalled = true;
48
+ error.pendingToolUse = true;
49
+ error.incompleteReason = reasonStr;
50
+ if (usage) error.partialUsage = usage;
51
+ failWith(error, options);
52
+ return;
53
+ }
35
54
  response.markMaxOutputIncomplete(reasonStr);
36
55
  completeTurn();
37
56
  return;
@@ -105,11 +124,11 @@ export function createTerminalFrameHandlers({ response, textRelay, midState, err
105
124
  failWith(responseDoneStatusError(status, `${errLabel} response.done unexpected status`), { markDone: true });
106
125
  return;
107
126
  }
108
- // Success-shaped response.done (status '' or 'completed') carries the
109
- // same optional end_turn, and the response's usage.
110
- response.noteTerminal(event.response);
111
- response.setEndTurn(_endTurnFromEvent(event));
112
- completeTurn();
127
+ // Success-shaped response.done (status '' or 'completed') is the same
128
+ // terminal as response.completed: usage, end_turn, and its output bundle
129
+ // reconciled through the same deduplicated collectors (calls that appear
130
+ // only in the bundle are created; unresolvable deferred calls fail).
131
+ onResponseCompleted(event);
113
132
  }
114
133
 
115
134
  function onResponseIncomplete(event) {
@@ -4,6 +4,7 @@
4
4
  * builder returns a tagged Error the stream loop stores as terminalError.
5
5
  */
6
6
  import { typedStatusFrom } from './retry-classifier.mjs';
7
+ import { applyErrorContract, markContentFilter } from './openai-error-contract.mjs';
7
8
  import { _httpStatusFromWsClose } from './openai-ws-events.mjs';
8
9
 
9
10
  /** A server `event.error` on any frame. Same wire-error contract as
@@ -17,10 +18,9 @@ export function serverErrorEventError(error, event) {
17
18
  try {
18
19
  err.payload = error;
19
20
  err.responseFailed = event;
20
- const typed = typedStatusFrom(error, event);
21
- if (typed) err.httpStatus = typed;
22
21
  const code = error.code ?? error.type ?? null;
23
22
  if (typeof code === 'string' && code) err.providerErrorCode = code;
23
+ applyErrorContract(err, { status: typedStatusFrom(error, event), error, event });
24
24
  } catch {}
25
25
  return err;
26
26
  }
@@ -32,23 +32,27 @@ export function serverErrorEventError(error, event) {
32
32
  export function responseFailedError(event, { label, fallbackMessage, providerErrorCode = false }) {
33
33
  const msg = event.response?.error?.message || event.error?.message || event.message || fallbackMessage;
34
34
  const err = Object.assign(new Error(`${label}: ${msg}`), { responseFailed: event });
35
- const typed = typedStatusFrom(event.response?.error, event.error, event);
36
- if (typed) err.httpStatus = typed;
35
+ const detail = event.response?.error || event.error || null;
37
36
  if (providerErrorCode) {
38
- const detail = event.response?.error || event.error || null;
39
37
  const code = detail?.code ?? detail?.type ?? null;
40
38
  if (typeof code === 'string' && code) err.providerErrorCode = code;
41
39
  }
42
- return err;
40
+ return applyErrorContract(err, {
41
+ status: typedStatusFrom(event.response?.error, event.error, event),
42
+ error: detail,
43
+ event,
44
+ });
43
45
  }
44
46
 
45
47
  /** response.incomplete (or response.done status 'incomplete') for a reason
46
- * other than max_output_tokens. */
48
+ * other than max_output_tokens. A content_filter stop is a typed policy
49
+ * refusal (code 'content_filter'), not an untyped failure. */
47
50
  export function responseIncompleteError(event, reasonStr, label) {
48
- return Object.assign(new Error(`${label}: ${reasonStr}`), {
51
+ const err = Object.assign(new Error(`${label}: ${reasonStr}`), {
49
52
  responseIncomplete: event,
50
53
  incompleteReason: reasonStr,
51
54
  });
55
+ return markContentFilter(err, reasonStr);
52
56
  }
53
57
 
54
58
  /** response.done with a status that is neither completed, failed nor incomplete. */
@@ -63,11 +67,14 @@ export function errorFrameError(event, label) {
63
67
  const errMsg = String(event.message || event.error?.message || 'unknown');
64
68
  const err = new Error(`${label}: ${errMsg}`);
65
69
  err.responseFailed = event;
66
- const typed = typedStatusFrom(event.error, event);
67
- if (typed) err.httpStatus = typed;
68
70
  const code = event.error?.code ?? event.error?.type ?? event.code ?? null;
69
71
  if (typeof code === 'string' && code) err.providerErrorCode = code;
70
- return err;
72
+ return applyErrorContract(err, {
73
+ status: typedStatusFrom(event.error, event),
74
+ code: typeof code === 'string' ? code : undefined,
75
+ error: event.error,
76
+ event,
77
+ });
71
78
  }
72
79
 
73
80
  /** The socket closed before a terminal frame. */