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
@@ -1,33 +1,44 @@
1
- import { getModelMetadataSync } from '../../../shared/llm/model-catalog.mjs';
1
+ import {
2
+ openAiCatalogMeta,
3
+ openAiSupportsExtendedRetention,
4
+ openAiUsesPromptCacheOptions,
5
+ } from './openai-model-capabilities.mjs';
2
6
 
3
- // Public Responses contracts are independent of the OAuth backend.
4
- // Match documented model IDs and dated snapshots, not unknown future families.
5
- // GPT-5.6 and later: prompt_cache_options caching and Fast mode.
6
- const GPT_56_PLUS_MODELS =
7
+ // Public Responses contracts are independent of the OAuth backend. Service
8
+ // tiers come from the model catalog (the service-tier price columns), so a
9
+ // model the catalog lists works without an edit. Only a model no catalog
10
+ // describes (cold install) falls back to the documented ids known before the
11
+ // catalogs carried these columns.
12
+ const PRE_CATALOG_GPT_56_PLUS =
7
13
  /^(?:gpt-6-(?:astra|sol|luna)|gpt-6\.1-sol|gpt-5\.6-(?:sol|terra|luna))(?:-\d{4}-\d{2}-\d{2})?$/;
8
-
9
- // OpenAI bills prompt-cache writes from GPT-5.6 on, and exactly those models
10
- // take prompt_cache_options and Fast mode. The id pattern is the offline
11
- // floor; a published cache-write price admits a later model without an edit
12
- // here, and a family no catalog lists yet stays out.
13
- // https://developers.openai.com/api/docs/guides/prompt-caching
14
- function isGpt56PlusModel(model) {
15
- const id = String(model || '').trim();
16
- if (!id) return false;
17
- return GPT_56_PLUS_MODELS.test(id) || getModelMetadataSync(id, 'openai')?.cacheWriteCostPerM > 0;
18
- }
19
- // Earlier models documented for Priority processing (now Fast mode).
20
- const EARLIER_FAST_MODELS = /^gpt-5\.(?:5|4|4-mini)(?:-\d{4}|$)/;
14
+ const PRE_CATALOG_EARLIER_FAST = /^gpt-5\.(?:5|4|4-mini)(?:-\d{4}|$)/;
15
+ const PRE_CATALOG_ULTRAFAST = /^(?:gpt-6-astra|gpt-6\.1-sol)(?:-\d{4}-\d{2}-\d{2})?$/;
16
+ const modelId = (model) => String(model?.id || model || '').trim();
21
17
 
22
18
  export function openAiDirectSupportsFast(model) {
23
- const id = String(model?.id || model || '').trim();
24
- return isGpt56PlusModel(id) || EARLIER_FAST_MODELS.test(id);
19
+ const meta = openAiCatalogMeta(model);
20
+ // The catalog's declaration (true or false) decides; a published Priority
21
+ // rate is the same declaration. A row silent on Fast keeps the documented ids.
22
+ if (typeof meta?.supportsFastMode === 'boolean') return meta.supportsFastMode;
23
+ if (meta?.fastPricing) return true;
24
+ const id = modelId(model);
25
+ return PRE_CATALOG_GPT_56_PLUS.test(id) || PRE_CATALOG_EARLIER_FAST.test(id);
25
26
  }
26
27
 
27
- const ULTRAFAST_MODELS = /^(?:gpt-6-astra|gpt-6\.1-sol)(?:-\d{4}-\d{2}-\d{2})?$/;
28
-
28
+ // A published Ultrafast rate (the `_ultrafast` price columns) is the tier's
29
+ // declaration; a row silent on it keeps the documented ids.
29
30
  export function openAiDirectSupportsUltrafast(model) {
30
- return ULTRAFAST_MODELS.test(String(model?.id || model || '').trim());
31
+ if (openAiCatalogMeta(model)?.ultrafastPricing) return true;
32
+ return PRE_CATALOG_ULTRAFAST.test(modelId(model));
33
+ }
34
+
35
+ // https://developers.openai.com/api/docs/guides/prompt-caching
36
+ // GPT-5.6 and later: prompt_cache_options.ttl. Earlier models: 24h
37
+ // prompt_cache_retention only on the documented extended-retention list;
38
+ // every other model gets no lifetime field (never inferred from pricing).
39
+ function promptCacheForm(model) {
40
+ if (openAiUsesPromptCacheOptions(model) || PRE_CATALOG_GPT_56_PLUS.test(modelId(model))) return 'options';
41
+ return openAiSupportsExtendedRetention(model) ? 'retention' : null;
31
42
  }
32
43
 
33
44
  export function applyOpenAIDirectCachePolicy(body, model, storeResponses) {
@@ -37,10 +48,8 @@ export function applyOpenAIDirectCachePolicy(body, model, storeResponses) {
37
48
  // Preserve the existing opt-out: no explicit cache-retention hint when
38
49
  // response storage is disabled. The provider's default cache still applies.
39
50
  if (!storeResponses) return body;
40
- if (isGpt56PlusModel(model)) {
41
- body.prompt_cache_options = { ttl: '30m' };
42
- } else {
43
- body.prompt_cache_retention = '24h';
44
- }
51
+ const form = promptCacheForm(model);
52
+ if (form === 'options') body.prompt_cache_options = { ttl: '30m' };
53
+ else if (form === 'retention') body.prompt_cache_retention = '24h';
45
54
  return body;
46
55
  }
@@ -0,0 +1,274 @@
1
+ /**
2
+ * openai-error-contract.mjs — the one place the OpenAI provider boundary
3
+ * stamps the shared error contract onto a thrown error:
4
+ *
5
+ * status / httpStatus typed HTTP status
6
+ * code lowercased error code/type from the JSON body or wire event
7
+ * headers response headers (HTTP, WS handshake, nested error.headers)
8
+ * retryAfterMs server advice, uncapped (Retry-After / Retry-After-Ms)
9
+ * resetAt epoch ms from quota reset fields (resets_at, resets_in_seconds)
10
+ *
11
+ * Pure: no I/O. Message text is never parsed for status or code.
12
+ */
13
+ import { retryAfterMsFromError, sleepWithAbort } from './retry-classifier.mjs';
14
+
15
+ const isObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
16
+
17
+ // Explicit quota / billing refusals: waiting never helps, so no retry layer
18
+ // may treat them as an ordinary rate limit.
19
+ const QUOTA_OR_BILLING_CODE_RE = /quota|billing|usage_limit|usage_not_included/;
20
+
21
+ export function isQuotaOrBillingCode(code) {
22
+ return QUOTA_OR_BILLING_CODE_RE.test(String(code || '').toLowerCase());
23
+ }
24
+
25
+ /**
26
+ * Parse an HTTP error body ONCE into its contract fields. `message` is the
27
+ * body's own message (untruncated); callers truncate for diagnostics.
28
+ */
29
+ export function parseErrorBody(text) {
30
+ let json = null;
31
+ try {
32
+ json = JSON.parse(String(text || ''));
33
+ } catch {}
34
+ const error = isObject(json?.error) ? json.error : isObject(json) ? json : null;
35
+ const rawCode = error?.code ?? error?.type ?? (typeof json?.error === 'string' ? json.error : null);
36
+ const code = typeof rawCode === 'string' && rawCode.trim() ? rawCode.trim().toLowerCase() : '';
37
+ const message = typeof error?.message === 'string' ? error.message : '';
38
+ return { json, error, code, message };
39
+ }
40
+
41
+ function epochMsFrom(value) {
42
+ if (typeof value === 'string' && value.trim() && !Number.isFinite(Number(value))) {
43
+ const parsed = Date.parse(value);
44
+ return Number.isNaN(parsed) ? 0 : parsed;
45
+ }
46
+ const n = Number(value);
47
+ if (!Number.isFinite(n) || n <= 0) return 0;
48
+ // Epoch seconds (the wire form) vs epoch milliseconds.
49
+ return n < 1e12 ? Math.round(n * 1000) : Math.round(n);
50
+ }
51
+
52
+ /** Absolute quota reset time (epoch ms) from the first source carrying one; 0 when none. */
53
+ export function resetAtFrom(...sources) {
54
+ for (const source of sources) {
55
+ if (!isObject(source)) continue;
56
+ const absolute = epochMsFrom(source.resets_at ?? source.reset_at ?? source.resetsAt);
57
+ if (absolute) return absolute;
58
+ const inSeconds = Number(source.resets_in_seconds ?? source.reset_in_seconds);
59
+ if (Number.isFinite(inSeconds) && inSeconds > 0) return Date.now() + Math.round(inSeconds * 1000);
60
+ }
61
+ return 0;
62
+ }
63
+
64
+ // ── User-facing messages for typed wire errors ───────────────────────────────
65
+ const QUOTA_EXCEEDED_MESSAGE = 'Quota exceeded. Check your plan and billing details.';
66
+ const USAGE_NOT_INCLUDED_MESSAGE =
67
+ 'To use Codex with your ChatGPT plan, upgrade to Plus: https://chatgpt.com/explore/plus.';
68
+ const SERVER_OVERLOADED_MESSAGE = 'Selected model is at capacity. Please try a different model.';
69
+ const WS_CONNECTION_LIMIT_MESSAGE =
70
+ 'Responses websocket connection limit reached (60 minutes). Create a new websocket connection to continue.';
71
+ const PREVIOUS_RESPONSE_NOT_FOUND_MESSAGE = 'Previous response was not found. Retrying the full request.';
72
+ const QUOTA_EXCEEDED_CODES = new Set([
73
+ 'insufficient_quota',
74
+ 'credit_balance_exhausted',
75
+ 'organization_spend_limit_exceeded',
76
+ 'project_spend_limit_exceeded',
77
+ 'organization_usage_limit_exceeded',
78
+ ]);
79
+ // Wire codes whose own message is empty fall back to this copy.
80
+ const FALLBACK_MESSAGES = Object.freeze({
81
+ websocket_connection_limit_reached: WS_CONNECTION_LIMIT_MESSAGE,
82
+ previous_response_not_found: PREVIOUS_RESPONSE_NOT_FOUND_MESSAGE,
83
+ });
84
+
85
+ function headerValue(headers, name) {
86
+ if (!headers || typeof headers !== 'object') return '';
87
+ if (typeof headers.get === 'function') return String(headers.get(name) ?? '').trim();
88
+ const lower = name.toLowerCase();
89
+ for (const [key, value] of Object.entries(headers)) {
90
+ if (key.toLowerCase() === lower) return String(Array.isArray(value) ? value[0] : (value ?? '')).trim();
91
+ }
92
+ return '';
93
+ }
94
+
95
+ function ordinalSuffix(day) {
96
+ if (day >= 11 && day <= 13) return 'th';
97
+ return { 1: 'st', 2: 'nd', 3: 'rd' }[day % 10] || 'th';
98
+ }
99
+
100
+ /** Retry timestamp: "3:04 PM" today, else "Mar 5th, 2026 3:04 PM" (local time). */
101
+ export function formatRetryTimestamp(resetsAtMs, now = Date.now()) {
102
+ const reset = new Date(resetsAtMs);
103
+ const time = reset.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
104
+ if (reset.toDateString() === new Date(now).toDateString()) return time;
105
+ const month = reset.toLocaleDateString('en-US', { month: 'short' });
106
+ return `${month} ${reset.getDate()}${ordinalSuffix(reset.getDate())}, ${reset.getFullYear()} ${time}`;
107
+ }
108
+
109
+ const WORKSPACE_REACHED_MESSAGES = Object.freeze({
110
+ workspace_owner_credits_depleted: 'Your workspace is out of credits. Add credits to continue.',
111
+ workspace_member_credits_depleted:
112
+ 'Your workspace is out of credits. Ask your workspace owner to refill in order to continue.',
113
+ workspace_owner_usage_limit_reached:
114
+ 'You hit your spend cap set in your workspace. Increase your spend cap to continue.',
115
+ workspace_member_usage_limit_reached:
116
+ 'You hit your spend cap set by the owner of your workspace. Ask an owner to increase your spend cap to continue.',
117
+ });
118
+ const PRO_PLANS = new Set(['pro', 'prolite', 'promax']);
119
+ const ADMIN_PLANS = new Set([
120
+ 'team',
121
+ 'self_serve_business_prolite',
122
+ 'self_serve_business_usage_based',
123
+ 'business',
124
+ 'ent26',
125
+ 'enterprise_cbp_automation',
126
+ 'enterprise_cbp_usage_based',
127
+ ]);
128
+
129
+ /**
130
+ * Usage-limit copy: per-limit name first, then workspace
131
+ * credits / spend cap, then the promo message, then the plan upgrade copy.
132
+ * @param {{planType?: string, resetsAtMs?: number, promo?: string, reachedType?: string, limitName?: string, now?: number}} f
133
+ */
134
+ export function usageLimitMessage({ planType, resetsAtMs, promo, reachedType, limitName, now } = {}) {
135
+ const at = resetsAtMs ? formatRetryTimestamp(resetsAtMs, now) : '';
136
+ const suffix = at ? ` Try again at ${at}.` : ' Try again later.';
137
+ const suffixOr = at ? ` or try again at ${at}.` : ' or try again later.';
138
+ const name = String(limitName || '').trim();
139
+ if (name && !/^(codex|gpt-reserve)$/i.test(name)) {
140
+ return `You’ve hit your usage limit for ${name}. Switch to another model now,${suffixOr}`;
141
+ }
142
+ const workspace = WORKSPACE_REACHED_MESSAGES[String(reachedType || '').toLowerCase()];
143
+ if (workspace) return workspace;
144
+ if (promo) return `You’ve hit your usage limit. ${promo},${suffixOr}`;
145
+ const plan = String(planType || '').toLowerCase();
146
+ if (plan === 'plus') {
147
+ return `You’ve hit your usage limit. Upgrade to Pro (https://chatgpt.com/explore/pro), visit https://chatgpt.com/settings/usage to purchase more credits${suffixOr}`;
148
+ }
149
+ if (ADMIN_PLANS.has(plan)) {
150
+ return `You’ve hit your usage limit. To get more access now, send a request to your admin${suffixOr}`;
151
+ }
152
+ if (plan === 'free' || plan === 'go') {
153
+ return `You’ve hit your usage limit. Upgrade to Plus to continue using Codex (https://chatgpt.com/explore/plus),${suffixOr}`;
154
+ }
155
+ if (PRO_PLANS.has(plan)) {
156
+ return `You’ve hit your usage limit. Visit https://chatgpt.com/settings/usage to purchase more credits${suffixOr}`;
157
+ }
158
+ return `You’ve hit your usage limit.${suffix}`;
159
+ }
160
+
161
+ /** The user-facing copy for a typed wire error, or '' when none applies. */
162
+ function typedWireErrorMessage({ code, type, error, headers, resetAt }) {
163
+ if (type === 'usage_limit_reached' || code === 'usage_limit_reached') {
164
+ const limitId = headerValue(headers, 'x-codex-active-limit').toLowerCase().replace(/_/g, '-');
165
+ return usageLimitMessage({
166
+ planType: error?.plan_type,
167
+ resetsAtMs: resetAt,
168
+ promo: headerValue(headers, 'x-codex-promo-message'),
169
+ reachedType: headerValue(headers, 'x-codex-rate-limit-reached-type'),
170
+ limitName: limitId ? headerValue(headers, `x-${limitId}-limit-name`) : '',
171
+ });
172
+ }
173
+ if (type === 'usage_not_included' || code === 'usage_not_included') return USAGE_NOT_INCLUDED_MESSAGE;
174
+ if (QUOTA_EXCEEDED_CODES.has(code) || type === 'insufficient_quota') return QUOTA_EXCEEDED_MESSAGE;
175
+ if (code === 'server_is_overloaded') return SERVER_OVERLOADED_MESSAGE;
176
+ const fallback = FALLBACK_MESSAGES[code];
177
+ return fallback && !String(error?.message || '').trim() ? fallback : '';
178
+ }
179
+
180
+ // Swap the server's own text inside `err.message` for the mapped copy; the
181
+ // original stays on providerError. `userMessage` always carries the copy.
182
+ function applyTypedWireMessage(err, mapped, original) {
183
+ err.userMessage = mapped;
184
+ const current = String(err.message || '');
185
+ const raw = String(original || '');
186
+ for (const needle of [raw, raw.slice(0, 200)]) {
187
+ if (needle && current.endsWith(needle)) {
188
+ err.message = current.slice(0, current.length - needle.length) + mapped;
189
+ return;
190
+ }
191
+ }
192
+ if (!raw && current) err.message = `${current}: ${mapped}`;
193
+ }
194
+ /**
195
+ * Stamp the contract onto `err`. Every field is optional input; only the
196
+ * ones present are written, and a field already on `err` is never replaced
197
+ * by an absent one.
198
+ *
199
+ * @param {Error} err
200
+ * @param {object} src
201
+ * @param {number} [src.status]
202
+ * @param {object} [src.headers] Headers or plain object
203
+ * @param {string} [src.code] already-lowercased code
204
+ * @param {object} [src.error] parsed error object (code/type/resets_at/headers)
205
+ * @param {object} [src.event] wire event the error was built from
206
+ */
207
+ export function applyErrorContract(err, { status, headers, code, error, event } = {}) {
208
+ try {
209
+ const n = Number(status);
210
+ if (Number.isFinite(n) && n >= 100 && n <= 599) {
211
+ err.status = n;
212
+ err.httpStatus = n;
213
+ }
214
+ const wireHeaders = headers ?? error?.headers ?? event?.error?.headers ?? event?.response?.error?.headers ?? event?.headers;
215
+ if (wireHeaders && typeof wireHeaders === 'object') err.headers = wireHeaders;
216
+ const rawCode = code ?? error?.code ?? error?.type ?? null;
217
+ if (typeof rawCode === 'string' && rawCode.trim()) err.code = rawCode.trim().toLowerCase();
218
+ const resetAt = resetAtFrom(error, event?.error, event?.response?.error, event);
219
+ if (resetAt) err.resetAt = resetAt;
220
+ const retryAfterMs = retryAfterMsFromError(err);
221
+ if (retryAfterMs != null) {
222
+ err.retryAfterMs = retryAfterMs;
223
+ // Server advice is a deadline captured once, so a
224
+ // later transport switch cannot restart or skip it.
225
+ if (err.retryAfterAt == null) err.retryAfterAt = Date.now() + retryAfterMs;
226
+ }
227
+ const type = typeof error?.type === 'string' ? error.type.trim().toLowerCase() : '';
228
+ const mapped = typedWireErrorMessage({ code: err.code || '', type, error, headers: err.headers, resetAt: err.resetAt });
229
+ if (mapped) applyTypedWireMessage(err, mapped, error?.message);
230
+ } catch {}
231
+ return err;
232
+ }
233
+
234
+ /**
235
+ * A response.incomplete with reason `content_filter` is a policy refusal:
236
+ * type it so no layer mistakes it for a transient or untyped failure. The
237
+ * wire event is deliberately NOT attached as `responseFailed` (that marker
238
+ * makes unknown codes default-retryable).
239
+ */
240
+ export function markContentFilter(err, reason) {
241
+ if (String(reason || '').trim().toLowerCase() !== 'content_filter') return err;
242
+ err.code = 'content_filter';
243
+ err.providerErrorCode = 'content_filter';
244
+ return err;
245
+ }
246
+
247
+ /**
248
+ * The error for a non-2xx HTTP response whose body has been read as `text`.
249
+ * The message carries a bounded diagnostic; the structured fields come from
250
+ * the full parsed body.
251
+ */
252
+ export function httpResponseError({ label, status, headers, text, initialResponse = false, diagnosticLimit = 200 }) {
253
+ const parsed = parseErrorBody(text);
254
+ const diagnostic = (parsed.message || String(text || '')).slice(0, diagnosticLimit);
255
+ const err = new Error(diagnostic ? `${label} ${status}: ${diagnostic}` : `${label} ${status}`);
256
+ if (initialResponse) err.initialResponseError = true;
257
+ if (parsed.error) err.providerError = parsed.error;
258
+ if (parsed.code) err.providerErrorCode = parsed.code;
259
+ return applyErrorContract(err, { status, headers, code: parsed.code, error: parsed.error, event: parsed.json });
260
+ }
261
+
262
+ // The route decides the HTTP/SSE label: the api-key `openai` provider is not OAuth.
263
+ export const httpLabel = (auth) => (auth?.type === 'openai-direct' ? 'OpenAI HTTP fallback' : 'OpenAI OAuth HTTP fallback');
264
+
265
+ /**
266
+ * Changing transport must not bypass the server's retry deadline.
267
+ * Sleeps until the deadline the failed attempt captured (abortable).
268
+ */
269
+ export async function waitForRetryDeadline(err, externalSignal, sleepFn) {
270
+ // retryAfterMsFromError reports what is left of the captured retryAfterAt.
271
+ const remaining = retryAfterMsFromError(err) ?? 0;
272
+ if (!(remaining > 0)) return;
273
+ await sleepWithAbort(remaining, externalSignal, sleepFn, 'OpenAI transport fallback wait aborted');
274
+ }
@@ -9,11 +9,17 @@
9
9
  import zlib from 'node:zlib';
10
10
  import { traceAgentFetch } from '../agent-trace.mjs';
11
11
  import { PROVIDER_HTTP_RESPONSE_TIMEOUT_MS, createTimeoutSignal } from '../stall-policy.mjs';
12
+ import { CODEX_REQUEST_RETRY_BACKOFF_MS, CODEX_RETRY_JITTER_RATIO } from './openai-retry-policy.mjs';
12
13
  import { classifyError, jitterDelayMs, retryAfterMsFromError, sleepWithAbort } from './retry-classifier.mjs';
14
+ import { emitProviderRetryStage } from './retry-executor.mjs';
15
+ import { adviceGatedRetry } from './retry-midstream.mjs';
16
+ import { TERMINAL_EDGE_STATUSES } from './retry-classification.mjs';
17
+ import { DETERMINISTIC_KINDS, providerErrorKind } from './provider-error-kind.mjs';
13
18
  import { readStreamOutcome } from './lib/stream-outcome.mjs';
14
19
  import { getLlmDispatcher, recycleLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
15
20
  import { CODEX_RESPONSES_URL } from './openai-codex-endpoints.mjs';
16
21
  import { captureCodexTurnState } from './openai-turn-state.mjs';
22
+ import { httpLabel, httpResponseError } from './openai-error-contract.mjs';
17
23
 
18
24
  // Public OpenAI Responses API endpoint for the api-key `openai` provider.
19
25
  // The openai-direct WS transport hits the same origin (openai-ws-pool
@@ -22,9 +28,28 @@ import { captureCodexTurnState } from './openai-turn-state.mjs';
22
28
  // openai-oauth. Same Responses SSE wire format, only endpoint + auth differ.
23
29
  const OPENAI_DIRECT_RESPONSES_URL = 'https://api.openai.com/v1/responses';
24
30
  const CODEX_REQUEST_MAX_RETRIES = 4;
25
- const CODEX_REQUEST_BACKOFF_MS = Object.freeze([200, 400, 800, 1600]);
26
- const CODEX_RETRY_JITTER_RATIO = 0.1;
31
+ // Advice-gated retry for the OpenAI request loops (same options the shared
32
+ // withRetry takes): an overload and an untyped 429 retry only with server advice.
33
+ const OPENAI_REQUEST_RETRY_OPTS = Object.freeze({
34
+ overloadRetryRequiresAdvice: true,
35
+ generic429RetryRequiresAdvice: true,
36
+ backoffMs: CODEX_REQUEST_RETRY_BACKOFF_MS,
37
+ retryJitterRatio: CODEX_RETRY_JITTER_RATIO,
38
+ });
27
39
 
40
+
41
+ // Request-layer retry: 5xx and typed transport
42
+ // failures only. 408 and 429 are NOT retried here; they surface to the outer
43
+ // stream-retry layer, which owns their budget and honors Retry-After.
44
+ // A deterministic refusal (quota, billing, entitlement, policy, auth,
45
+ // permission, invalid request) is terminal whatever status carries it.
46
+ function isRetryableHttpFailure(err) {
47
+ const status = err.httpStatus;
48
+ if (!(status >= 500 && status <= 599) || TERMINAL_EDGE_STATUSES.has(status)) return false;
49
+ const { kind } = providerErrorKind(err);
50
+ if (DETERMINISTIC_KINDS.has(kind)) return false;
51
+ return adviceGatedRetry(err, OPENAI_REQUEST_RETRY_OPTS) !== false;
52
+ }
28
53
  // Request-body zstd gate. Namespace import: on Node runtimes without zlib
29
54
  // zstd bindings the named export would fail at module load, so the call site
30
55
  // typeof-guards zlib.zstdCompressSync instead.
@@ -65,13 +90,15 @@ async function postWithRetries({
65
90
  onStageChange,
66
91
  _sleepFn,
67
92
  }) {
93
+ const label = httpLabel(auth);
68
94
  let bodyForSend = encodeRequestBody(auth, rawBytes);
69
95
  let response;
96
+ let httpError = null;
70
97
  for (let attempt = 0; attempt <= CODEX_REQUEST_MAX_RETRIES; attempt++) {
71
98
  const headerTimeout = createTimeoutSignal(
72
99
  totalTimeout.signal,
73
100
  PROVIDER_HTTP_RESPONSE_TIMEOUT_MS,
74
- 'OpenAI OAuth HTTP fallback initial response'
101
+ `${label} initial response`
75
102
  );
76
103
  let requestError = null;
77
104
  try {
@@ -113,7 +140,19 @@ async function postWithRetries({
113
140
  attempt--;
114
141
  continue;
115
142
  }
116
- const retryableStatus = response && response.status >= 500 && response.status <= 599;
143
+ // The error body is read exactly once, here, into the contract fields.
144
+ httpError = null;
145
+ if (response && !response.ok) {
146
+ const text = await response.text().catch(() => '');
147
+ httpError = httpResponseError({
148
+ label,
149
+ status: response.status,
150
+ headers: response.headers,
151
+ text,
152
+ initialResponse: true,
153
+ });
154
+ }
155
+ const retryableStatus = httpError !== null && isRetryableHttpFailure(httpError);
117
156
  // Typed transient transport failures only (errno / SDK connection
118
157
  // type). An unknown pre-response failure throws immediately instead of
119
158
  // re-issuing the POST.
@@ -135,30 +174,36 @@ async function postWithRetries({
135
174
  // Reissuing the POST is a REPLAY: allowed for a typed transient
136
175
  // failure of the initial request, denied once the failure carries
137
176
  // exposure evidence (relayed output / dispatched tool call).
138
- const attemptFailure =
139
- requestError ||
140
- Object.assign(new Error(`OpenAI OAuth HTTP fallback ${response.status}`), {
141
- httpStatus: response.status,
142
- headers: response.headers,
143
- initialResponseError: true,
144
- });
177
+ const attemptFailure = requestError || httpError;
145
178
  if (readStreamOutcome(attemptFailure).replaySafe !== true) {
146
- if (response) await response.arrayBuffer().catch(() => {});
147
179
  totalTimeout.cleanup();
148
180
  throw attemptFailure;
149
181
  }
150
- // A non-success response has not exposed any streamed output. Drain
151
- // its body before reissuing so the dispatcher can reuse the socket.
152
- if (response) await response.arrayBuffer().catch(() => {});
153
182
  // Server advice (Retry-After / Retry-After-Ms) replaces the local curve.
154
- const raw = CODEX_REQUEST_BACKOFF_MS[attempt];
155
- await sleepWithAbort(
156
- retryAfterMsFromError(attemptFailure) ?? jitterDelayMs(raw, CODEX_RETRY_JITTER_RATIO),
157
- externalSignal,
158
- _sleepFn,
159
- 'OpenAI OAuth HTTP request retry backoff aborted'
160
- );
183
+ // Uncapped for retryable errors; the attempt count is
184
+ // the bound, and the abort signal cancels the wait.
185
+ // The shared schedule carries a leading duplicate (withRetry convention).
186
+ const raw = OPENAI_REQUEST_RETRY_OPTS.backoffMs[attempt + 1];
187
+ const delayMs = retryAfterMsFromError(attemptFailure) ?? jitterDelayMs(raw, OPENAI_REQUEST_RETRY_OPTS.retryJitterRatio);
188
+ emitProviderRetryStage(onStageChange, {
189
+ attempt: attempt + 2,
190
+ maxAttempts: CODEX_REQUEST_MAX_RETRIES + 1,
191
+ lastErr: attemptFailure,
192
+ delayMs,
193
+ });
194
+ try {
195
+ await sleepWithAbort(
196
+ delayMs,
197
+ externalSignal || totalTimeout.signal,
198
+ _sleepFn,
199
+ `${label} request retry backoff aborted`
200
+ );
201
+ } catch (abortErr) {
202
+ totalTimeout.cleanup();
203
+ throw abortErr;
204
+ }
161
205
  response = undefined;
206
+ httpError = null;
162
207
  continue;
163
208
  }
164
209
  if (requestError) {
@@ -169,7 +214,7 @@ async function postWithRetries({
169
214
  }
170
215
  break;
171
216
  }
172
- return response;
217
+ return { response, httpError };
173
218
  }
174
219
 
175
220
  export async function openHttpSseResponse({
@@ -187,7 +232,7 @@ export async function openHttpSseResponse({
187
232
  }) {
188
233
  const fetchStartedAt = Date.now();
189
234
  const responsesUrl = auth?.type === 'openai-direct' ? OPENAI_DIRECT_RESPONSES_URL : CODEX_RESPONSES_URL;
190
- const response = await postWithRetries({
235
+ const { response, httpError } = await postWithRetries({
191
236
  responsesUrl,
192
237
  headers,
193
238
  rawBytes: Buffer.from(JSON.stringify(body)),
@@ -208,14 +253,9 @@ export async function openHttpSseResponse({
208
253
  transport: 'http',
209
254
  });
210
255
 
211
- if (!response.ok) {
212
- const text = await response.text().catch(() => '');
213
- const err = new Error(`OpenAI OAuth HTTP fallback ${response.status}: ${text.slice(0, 200)}`);
214
- err.httpStatus = response.status;
215
- err.headers = response.headers;
216
- err.initialResponseError = true;
256
+ if (httpError) {
217
257
  totalTimeout.cleanup();
218
- throw err;
258
+ throw httpError;
219
259
  }
220
260
  if (auth?.type !== 'openai-direct') {
221
261
  const responseTurnState = response.headers?.get?.('x-codex-turn-state');
@@ -223,7 +263,7 @@ export async function openHttpSseResponse({
223
263
  }
224
264
  if (!response.body) {
225
265
  totalTimeout.cleanup();
226
- throw Object.assign(new Error('OpenAI OAuth HTTP fallback returned no response body'), {
266
+ throw Object.assign(new Error(`${httpLabel(auth)} returned no response body`), {
227
267
  initialResponseError: true,
228
268
  });
229
269
  }
@@ -6,6 +6,8 @@
6
6
  */
7
7
  import { recomputeToolInFlight } from '../response-state.mjs';
8
8
  import { parseJsonObject } from '../response-items.mjs';
9
+ import { withToolCallNamespace } from '../../custom-tool-wire.mjs';
10
+ import { isIncompleteToolItem } from '../../lib/responses-terminal-fields.mjs';
9
11
 
10
12
  function outputItemKind(item) {
11
13
  if (item.type === 'reasoning') return 'reasoning';
@@ -19,10 +21,10 @@ export function createOutputItemEvents({ state, items, meaningful }) {
19
21
  const onOutputItemAdded = (item) => {
20
22
  if (item?.type === 'function_call') {
21
23
  toolTracker.mark(item);
22
- state.pendingCalls.set(item.id || '', {
23
- name: item.name || '',
24
- callId: item.call_id || '',
25
- });
24
+ state.pendingCalls.set(
25
+ item.id || '',
26
+ withToolCallNamespace({ name: item.name || '', callId: item.call_id || '' }, item)
27
+ );
26
28
  state.toolInFlight = true;
27
29
  } else if (item?.type === 'tool_search_call') {
28
30
  // Mark tool_search as in-flight the moment the item is added,
@@ -66,12 +68,15 @@ export function createOutputItemEvents({ state, items, meaningful }) {
66
68
  meaningful('tool');
67
69
  return;
68
70
  }
69
- const call = {
70
- id: pending?.callId || event.call_id || '',
71
- name: pending?.name || event.name || '',
72
- arguments: parseJsonObject(event.arguments),
73
- _pendingItemId: itemId,
74
- };
71
+ const call = withToolCallNamespace(
72
+ {
73
+ id: pending?.callId || event.call_id || '',
74
+ name: pending?.name || event.name || '',
75
+ arguments: parseJsonObject(event.arguments),
76
+ _pendingItemId: itemId,
77
+ },
78
+ pending
79
+ );
75
80
  state.toolCalls.push(call);
76
81
  if (call.id && call.name) {
77
82
  delete call._pendingItemId;
@@ -81,9 +86,17 @@ export function createOutputItemEvents({ state, items, meaningful }) {
81
86
  };
82
87
 
83
88
  const onOutputItemDone = (item) => {
89
+ if (isIncompleteToolItem(item)) {
90
+ // Server-truncated call: stays in flight, never collected or replayed.
91
+ toolTracker.mark(item);
92
+ state.toolInFlight = true;
93
+ meaningful('tool');
94
+ return;
95
+ }
84
96
  items.pushResponseItem(item);
85
97
  items.pushReasoningItem(item);
86
98
  items.pushWebSearchCall(item);
99
+ state.refusals.absorbMessage(item);
87
100
  if (item.type === 'function_call') {
88
101
  const tc = state.toolCalls.find((t) => t._pendingItemId === (item.id || ''));
89
102
  if (tc) items.completePendingCall(tc, item);