@iislee/opencodex 2.11.0 → 2.35.0

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 (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -9,7 +9,8 @@ import { parseRequest } from "../../responses/parser";
9
9
  import { buildCompactV1Output, COMPACT_PROMPT, decodeCompactionSummary, extractCompactUserMessages } from "../../responses/compaction";
10
10
  import { FORWARD_HEADERS, sanitizeReasoningInputContent } from "../../adapters/openai-responses";
11
11
  import { expandPreviousResponseInput, previousResponseProviderState, rememberResponseState } from "../../responses/state";
12
- import { routeModel } from "../../router";
12
+ import { NoEligiblePolicyCandidateError, routeModel } from "../../router";
13
+ import { evidenceFromBody } from "../../routing/request-evidence";
13
14
  import {
14
15
  advanceComboAfterFailure,
15
16
  comboDefaultEffort,
@@ -27,7 +28,7 @@ import {
27
28
  import { isInjectionDebugEnabled } from "../../lib/debug-settings";
28
29
  import { injectionDebugLog } from "../../lib/injection-debug-log";
29
30
  import { modelInList, namespacedToolName } from "../../types";
30
- import type { AdapterEvent, OcxConfig, OcxParsedRequest, OcxProviderConfig, OcxProviderContinuationState, OcxUsage } from "../../types";
31
+ import type { AdapterEvent, CodexAccountMode, OcxConfig, OcxParsedRequest, OcxProviderConfig, OcxProviderContinuationState, OcxUsage } from "../../types";
31
32
  import {
32
33
  forceRefreshOAuthAccessSnapshot,
33
34
  getOAuthCredentialApiBaseUrl,
@@ -41,17 +42,14 @@ import { describeImagesInPlace, planVisionSidecar, shouldResolveOpenAiVisionSide
41
42
  import { createAdapterEventQueue, preflightAdapterEvents } from "../../adapters/run-turn-queue";
42
43
  import {
43
44
  applyCodexAuthContextToProvider,
44
- CodexAccountCooldownError,
45
- cooldownErrorResponse,
46
- CodexAuthContextError,
47
- CodexDirectAuthenticationError,
48
- CodexPoolAuthenticationError,
49
- CodexThreadAffinityExpiredError,
45
+ CodexMainProfileDrainingError,
50
46
  headersForCodexAuthContext,
47
+ materializeCodexUpstreamAuth,
51
48
  isCodexAuthContextUsable,
52
49
  resolveCodexAuthContext,
53
50
  codexProbeLeaseId,
54
51
  codexProbeQuotaScope,
52
+ releaseCodexAuthContextProbeLease,
55
53
  type CodexAuthContext,
56
54
  } from "../../codex/auth-context";
57
55
  import {
@@ -59,10 +57,27 @@ import {
59
57
  recordCodexUpstreamOutcome,
60
58
  type CodexUpstreamOutcome,
61
59
  } from "../../codex/routing";
62
- import { fetchWithResetRetry, fetchWithTransientRetry, applyUpstreamRecoveryInit } from "../../lib/upstream-retry";
60
+ import {
61
+ fetchWithResetRetry,
62
+ fetchWithTransientRetry,
63
+ applyUpstreamRecoveryInit,
64
+ type UpstreamSendRecovery,
65
+ } from "../../lib/upstream-retry";
66
+ import { classifyTransportFailureKind, transportErrorCode } from "../../lib/upstream-reachability";
67
+ import {
68
+ acquireUpstreamHostAdmission,
69
+ disableUpstreamHostCircuitForKey,
70
+ normalizeUpstreamHostCircuitThreshold,
71
+ recordUpstreamHostFailure,
72
+ releaseUpstreamHostAdmission,
73
+ resetUpstreamHostHealth,
74
+ upstreamHostHealthKey,
75
+ type UpstreamHostAdmissionLease,
76
+ } from "../../codex/upstream-host-health";
63
77
  import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "../auth-cors";
78
+ import type { DataPlaneAdmission } from "../auth-cors";
64
79
  import { listOpenAiForwardSidecarCandidates, resolveFirstUsableOpenAiSidecar, type ResolvedOpenAiForwardSidecar } from "../../providers/openai-sidecar";
65
- import { isCanonicalOpenAiForwardProvider, supportsNativeResponsesCompactEndpoint } from "../../providers/openai-tiers";
80
+ import { CODEX_FORWARD_BASE_URL, isCanonicalOpenAiForwardProvider, supportsNativeResponsesCompactEndpoint } from "../../providers/openai-tiers";
66
81
  import { slugsEquivalent } from "../../providers/slug-codec";
67
82
  import { applyOpenAiVirtualModel, resolveOpenAiCompactModel } from "../../providers/openai-virtual-models";
68
83
  import { isUsageDebugEnabled } from "../../usage/debug";
@@ -72,7 +87,8 @@ import { hasKeyPoolFailover, rotateProviderTransportOn429 } from "../../provider
72
87
  import { shouldAttemptImageTierRetry } from "../image-retry";
73
88
  import { resolveProviderTransport } from "../../providers/xai-transport";
74
89
  import type { WsData } from "../ws-bridge";
75
- import { registerTurn, trackStreamLifetime, unregisterTurn } from "../lifecycle";
90
+ import { codexAccountSelectionForTurn, registerTurn, trackStreamLifetime, unregisterTurn } from "../lifecycle";
91
+ import type { AdmissionLease } from "../../lib/admission";
76
92
  import { redactSecretString } from "../../lib/redact";
77
93
  import { readBoundedResponseBody } from "../../lib/bounded-body";
78
94
  import { supportedLadderFor } from "../effort-policy";
@@ -99,9 +115,18 @@ import {
99
115
  } from "../relay";
100
116
  import { hasResponsesItemIdRepair, relaySseWithResponsesItemIdRepair } from "../responses-item-id-repair";
101
117
  import type { EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
118
+ import { codexAuthContextLogLabel } from "../../codex/account-label";
102
119
 
103
- import { decodeRequestErrorResponse, handleResponses, usesCodexForwardPoolAuth } from "./core";
104
- import { fetchWithHeaderTimeout, providerFetch, safeHostLabel } from "./fetch-helpers";
120
+ import {
121
+ codexAccountGatedCanonicalWireModel,
122
+ decodeRequestErrorResponse,
123
+ handleResponses,
124
+ preAuthUpstreamHostCircuitKey,
125
+ upstreamHostCircuitOpenResponse,
126
+ usesCodexForwardPoolAuth,
127
+ } from "./core";
128
+ import { fetchWithHeaderTimeout, providerFetch, safeHostLabel, safeOriginLabel } from "./fetch-helpers";
129
+ import { mapCodexAuthContextErrorToResponse } from "./codex-auth-error";
105
130
 
106
131
  export const COMPACT_RESPONSE_MAX_BYTES = 32 * 1024 * 1024;
107
132
 
@@ -117,10 +142,88 @@ export function compactResponseTooLargeError(): Response {
117
142
 
118
143
 
119
144
 
145
+ /**
146
+ * Resolve one eligible pool account other than `excludeAccountId`, and build everything
147
+ * the alternate send needs. Returns null when no alternate exists or construction fails,
148
+ * in which case the caller keeps the first account's rejection intact.
149
+ *
150
+ * Mirrors the auth resolution the native compact branch already does for the first
151
+ * account, so the alternate is built the same way rather than through a second,
152
+ * divergent path.
153
+ */
154
+ async function resolveAlternateCompactContext(args: {
155
+ req: Request;
156
+ config: OcxConfig;
157
+ route: { provider: OcxProviderConfig; codexAccountMode?: CodexAccountMode };
158
+ selectedModelId: string | undefined;
159
+ excludeAccountId: string | null;
160
+ turnAdmissionLease?: AdmissionLease;
161
+ }): Promise<{ authCtx: CodexAuthContext; provider: OcxProviderConfig; headers: Headers } | null> {
162
+ const { req, config, route, selectedModelId, excludeAccountId, turnAdmissionLease } = args;
163
+ if (!route.codexAccountMode || !excludeAccountId) return null;
164
+ try {
165
+ const authCtx = await resolveCodexAuthContext(req.headers, config, route.codexAccountMode, {
166
+ ...(selectedModelId ? { modelId: selectedModelId } : {}),
167
+ excludeAccountId,
168
+ beginCodexAccountSelection: codexAccountSelectionForTurn(turnAdmissionLease),
169
+ });
170
+ if (!authCtx.accountId || authCtx.accountId === excludeAccountId) return null;
171
+ const provider = applyCodexAuthContextToProvider(route.provider, authCtx, route.codexAccountMode);
172
+ const headers = new Headers({ "content-type": "application/json" });
173
+ const selected = headersForCodexAuthContext(req.headers, authCtx);
174
+ for (const name of FORWARD_HEADERS) {
175
+ const value = selected.get(name);
176
+ if (value) headers.set(name, value);
177
+ }
178
+ const override = (provider as { _codexAccountOverride?: { accessToken: string; chatgptAccountId: string } })._codexAccountOverride;
179
+ if (override) {
180
+ headers.set("authorization", `Bearer ${override.accessToken}`);
181
+ headers.set("chatgpt-account-id", override.chatgptAccountId);
182
+ }
183
+ if (provider.apiKey) headers.set("authorization", `Bearer ${resolveEnvValue(provider.apiKey)}`);
184
+ return { authCtx, provider, headers };
185
+ } catch (err) {
186
+ if (err instanceof CodexMainProfileDrainingError) {
187
+ // The native-main fence can start after account A has already rejected the
188
+ // request. Treat the now-fenced main profile as no alternate and preserve A's
189
+ // real rejection instead of replacing it with a synthetic drain response.
190
+ return null;
191
+ }
192
+ // No eligible alternate (all cooled, affinity expired, reauth needed) — the caller
193
+ // returns the first account's rejection unchanged, which is today's behavior.
194
+ return null;
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Headers a client needs to back off correctly after a pool rejection. The buffered
200
+ * response is rebuilt from scratch, so anything not listed here is dropped — which is
201
+ * what silently discarded `Retry-After` and the reset hints from a 429 before.
202
+ * Deliberately narrow: no hop-by-hop headers, no content-length (the buffered body sets
203
+ * its own), no cookies.
204
+ */
205
+ const COMPACT_PASSTHROUGH_HEADERS = [
206
+ "retry-after",
207
+ "x-codex-primary-reset-at",
208
+ "x-codex-secondary-reset-at",
209
+ "x-codex-tertiary-reset-at",
210
+ // A relayed 3xx keeps its Location so the client can follow it (#914).
211
+ "location",
212
+ ];
213
+
214
+ function compactResponseHeaders(upstream: Response): Headers {
215
+ const headers = new Headers({ "Content-Type": upstream.headers.get("content-type") ?? "application/json" });
216
+ for (const name of COMPACT_PASSTHROUGH_HEADERS) {
217
+ const value = upstream.headers.get(name);
218
+ if (value) headers.set(name, value);
219
+ }
220
+ return headers;
221
+ }
222
+
120
223
  export async function bufferCompactResponse(upstream: Response, signal: AbortSignal): Promise<Response> {
121
224
  const reader = upstream.body?.getReader();
122
- const contentType = upstream.headers.get("content-type") ?? "application/json";
123
- if (!reader) return new Response(null, { status: upstream.status, headers: { "Content-Type": contentType } });
225
+ const headers = compactResponseHeaders(upstream);
226
+ if (!reader) return new Response(null, { status: upstream.status, statusText: upstream.statusText, headers });
124
227
  const declaredLength = Number(upstream.headers.get("content-length"));
125
228
  if (Number.isFinite(declaredLength) && declaredLength > COMPACT_RESPONSE_MAX_BYTES) {
126
229
  await reader.cancel("compact_response_too_large").catch(() => undefined);
@@ -153,7 +256,7 @@ export async function bufferCompactResponse(upstream: Response, signal: AbortSig
153
256
  body.set(chunk, offset);
154
257
  offset += chunk.byteLength;
155
258
  }
156
- return new Response(body, { status: upstream.status, headers: { "Content-Type": contentType } });
259
+ return new Response(body, { status: upstream.status, statusText: upstream.statusText, headers });
157
260
  }
158
261
 
159
262
 
@@ -162,6 +265,8 @@ export async function handleResponsesCompact(
162
265
  req: Request,
163
266
  config: OcxConfig,
164
267
  logCtx: RequestLogContext,
268
+ turnAdmissionLease?: AdmissionLease,
269
+ admission?: DataPlaneAdmission,
165
270
  ): Promise<Response> {
166
271
  let body: unknown;
167
272
  try {
@@ -179,14 +284,32 @@ export async function handleResponsesCompact(
179
284
 
180
285
  let route;
181
286
  try {
182
- route = routeModel(config, raw.model);
287
+ // Compact requests route through the same policy evaluation as normal
288
+ // turns, so body-derived evidence (tools/image) must reach the first
289
+ // evaluation too - not only the later handleResponses dispatch.
290
+ route = routeModel(config, raw.model, evidenceFromBody(raw));
183
291
  } catch (err) {
292
+ if (err instanceof NoEligiblePolicyCandidateError) {
293
+ // Persist the evaluation trace (per-candidate exclusions + the
294
+ // no-eligible reason) so a failed compact policy request stays
295
+ // auditable, matching the other request handlers.
296
+ logCtx.routeDecision = err.trace;
297
+ }
184
298
  return formatErrorResponse(404, "invalid_request_error", err instanceof Error ? err.message : String(err));
185
299
  }
186
300
  const selectedModelId = route.modelId;
301
+ // Derive from the RESOLVED route model, not the caller's raw string. An account-qualified
302
+ // selector like `side/gpt-daybreak-blue-latest` does not match the gated map — `slugsEquivalent`
303
+ // reads the account namespace as a routed provider prefix — so keying on `raw.model` sent
304
+ // exactly the selector form back down the native compact endpoint this guard exists to avoid.
305
+ // `route.modelId` is the same value `applyCodexAccountGatedWireNormalization` uses in core.ts.
306
+ const accountGatedCompactWireModel = codexAccountGatedCanonicalWireModel(selectedModelId);
187
307
  logCtx.requestedModel = raw.model;
188
308
  logCtx.model = selectedModelId;
189
- logCtx.provider = route.providerName;
309
+ logCtx.routeDecision = route.routeDecision;
310
+ logCtx.provider = route.codexAccountNamespace
311
+ ? `${route.providerName}-${route.codexAccountNamespace}`
312
+ : route.providerName;
190
313
  logCtx.providerAdapter = route.provider.adapter;
191
314
  const virtual = resolveOpenAiCompactModel(route.providerName, selectedModelId);
192
315
  if (virtual) {
@@ -197,7 +320,13 @@ export async function handleResponsesCompact(
197
320
  logCtx.resolvedModel = route.modelId;
198
321
  }
199
322
 
200
- if (route.codexAccountMode === "direct") {
323
+ // #1686: a bearer-presented admission secret is one of ours, so the stored main credential
324
+ // is substituted below instead of the caller bearer being forwarded.
325
+ // #2132: and only when the route is a native Codex one, which is the only route that can
326
+ // consume that credential. See the longer note in core.ts resolveResponsesCodexAuth.
327
+ const substituteMainCredential = admission?.source === "bearer"
328
+ && route.codexAccountMode !== undefined;
329
+ if (route.codexAccountMode === "direct" && !substituteMainCredential) {
201
330
  try { validateForwardAdmissionCredential(req.headers, config); }
202
331
  catch (err) {
203
332
  if (err instanceof ForwardAdmissionCredentialError) return formatErrorResponse(401, "authentication_error", err.message);
@@ -208,18 +337,45 @@ export async function handleResponsesCompact(
208
337
  // Native /responses/compact exists on the canonical ChatGPT backend and on the
209
338
  // official OpenAI API. Any other Responses-shaped gateway must take the routed
210
339
  // summarizer path below, or compaction fails against an endpoint it never had (#422).
211
- if (supportsNativeResponsesCompactEndpoint(route.providerName, route.provider)) {
340
+ if (supportsNativeResponsesCompactEndpoint(route.providerName, route.provider) && !accountGatedCompactWireModel) {
341
+ if (req.signal.aborted) {
342
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
343
+ }
344
+ // The enclosing native-compact guard already restricts this path to
345
+ // supported backends, so compact intentionally does not require the
346
+ // regular Responses adapter check here.
347
+ const preAuthCompactHostKey = preAuthUpstreamHostCircuitKey(route, config, {
348
+ requireResponsesAdapter: false,
349
+ });
350
+ let compactHostAdmissionLease: UpstreamHostAdmissionLease | null = null;
351
+ let authCtx: CodexAuthContext = { kind: "main", accountId: null };
352
+ if (preAuthCompactHostKey) {
353
+ const admission = acquireUpstreamHostAdmission(
354
+ preAuthCompactHostKey,
355
+ config.upstreamHostCircuitThreshold,
356
+ );
357
+ if (admission.kind === "blocked") {
358
+ return upstreamHostCircuitOpenResponse(admission.retryAfterSeconds);
359
+ }
360
+ compactHostAdmissionLease = admission.lease;
361
+ }
362
+ try {
212
363
  // Native ChatGPT/OpenAI model: forward the compact request verbatim to the real backend.
213
364
  // Resolve the SAME pool/thread auth context as /v1/responses — forwarding the caller's raw
214
365
  // headers would run compaction on the wrong account (or 401) whenever a pool account is
215
366
  // active for this thread while normal turns succeed.
216
367
  let compactProvider = route.provider;
217
- let authCtx: CodexAuthContext = { kind: "main", accountId: null };
218
368
  const headers = new Headers({ "content-type": "application/json" });
219
369
  try {
220
370
  if (route.codexAccountMode) {
221
- authCtx = await resolveCodexAuthContext(req.headers, config, route.codexAccountMode, { modelId: selectedModelId });
222
- const selected = headersForCodexAuthContext(req.headers, authCtx);
371
+ authCtx = await resolveCodexAuthContext(req.headers, config, route.codexAccountMode, {
372
+ accountId: route.codexAccountId,
373
+ modelId: selectedModelId,
374
+ substituteMainCredentialForDirect: substituteMainCredential,
375
+ beginCodexAccountSelection: codexAccountSelectionForTurn(turnAdmissionLease),
376
+ });
377
+ logCtx.accountLogLabel = codexAuthContextLogLabel(authCtx, config);
378
+ const selected = materializeCodexUpstreamAuth(req.headers, authCtx, { substituteMainCredential });
223
379
  compactProvider = applyCodexAuthContextToProvider(route.provider, authCtx, route.codexAccountMode);
224
380
  for (const name of FORWARD_HEADERS) {
225
381
  const value = selected.get(name);
@@ -232,74 +388,246 @@ export async function handleResponsesCompact(
232
388
  }
233
389
  }
234
390
  } catch (err) {
235
- if (err instanceof CodexAccountCooldownError) {
236
- return cooldownErrorResponse(err);
237
- }
238
- if (err instanceof CodexThreadAffinityExpiredError) {
239
- return formatErrorResponse(409, "invalid_request_error", "Codex thread account affinity expired; start a new session");
240
- }
241
- if (err instanceof CodexAuthContextError) {
242
- return formatErrorResponse(401, "authentication_error", "Selected Codex account needs reauthentication");
243
- }
244
- if (err instanceof CodexPoolAuthenticationError || err instanceof CodexDirectAuthenticationError) {
245
- return formatErrorResponse(401, "authentication_error", err.message);
246
- }
391
+ const response = mapCodexAuthContextErrorToResponse(err, {
392
+ accountSelector: route.codexAccountNamespace,
393
+ now: Date.now(),
394
+ });
395
+ if (response) return response;
247
396
  throw err;
248
397
  }
249
- const base = (compactProvider.baseUrl ?? "").replace(/\/$/, "");
250
- if (compactProvider.apiKey) headers.set("authorization", `Bearer ${resolveEnvValue(compactProvider.apiKey)}`);
398
+ const base = isCanonicalOpenAiForwardProvider(compactProvider)
399
+ ? CODEX_FORWARD_BASE_URL
400
+ : (compactProvider.baseUrl ?? "").replace(/\/+$/, "");
401
+ if (compactProvider.authMode !== "forward" && compactProvider.apiKey) {
402
+ headers.set("authorization", `Bearer ${resolveEnvValue(compactProvider.apiKey)}`);
403
+ }
251
404
  const { reasoning: _reasoning, ...compactBodyRaw } = raw as typeof raw & { reasoning?: unknown };
252
405
  // The regular /v1/responses path applies sanitizeReasoningInputContent via the adapter's
253
406
  // buildRequest, but the compact endpoint forwards directly. Apply the same sanitizer here
254
407
  // so routed-model reasoning items (reasoning_text content) don't 400 the ChatGPT backend.
255
408
  const compactBody = sanitizeReasoningInputContent(compactBodyRaw) as typeof compactBodyRaw;
256
409
  const compactUrl = `${base}/responses/compact`;
257
- const compactThreadId = req.headers.get("x-codex-parent-thread-id");
410
+ const actualCompactHostKey = upstreamHostHealthKey(
411
+ route.providerName,
412
+ safeOriginLabel(compactUrl),
413
+ );
414
+ const compactHostKey = compactProvider.authMode === "forward"
415
+ ? actualCompactHostKey
416
+ : null;
417
+ const compactHostCircuitEnabled = compactHostKey !== null
418
+ && normalizeUpstreamHostCircuitThreshold(config.upstreamHostCircuitThreshold) > 0;
419
+ if (compactHostKey !== null && !compactHostCircuitEnabled) {
420
+ disableUpstreamHostCircuitForKey(actualCompactHostKey);
421
+ }
422
+ if (compactHostAdmissionLease && compactHostAdmissionLease.key !== compactHostKey) {
423
+ releaseCodexAuthContextProbeLease(authCtx);
424
+ return formatErrorResponse(502, "upstream_error", "Provider host changed after circuit admission");
425
+ }
426
+ if (req.signal.aborted) {
427
+ releaseCodexAuthContextProbeLease(authCtx);
428
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
429
+ }
430
+ if (!compactHostAdmissionLease && compactHostCircuitEnabled) {
431
+ const admission = acquireUpstreamHostAdmission(
432
+ compactHostKey!,
433
+ config.upstreamHostCircuitThreshold,
434
+ );
435
+ if (admission.kind === "blocked") {
436
+ releaseCodexAuthContextProbeLease(authCtx);
437
+ return upstreamHostCircuitOpenResponse(admission.retryAfterSeconds);
438
+ }
439
+ compactHostAdmissionLease = admission.lease;
440
+ }
441
+ const settleObservedCompactHostResponse = (): void => {
442
+ if (compactHostCircuitEnabled) {
443
+ resetUpstreamHostHealth(actualCompactHostKey, compactHostAdmissionLease);
444
+ } else {
445
+ resetUpstreamHostHealth(actualCompactHostKey);
446
+ }
447
+ compactHostAdmissionLease = null;
448
+ };
258
449
  const connectMs = config.connectTimeoutMs ?? 200_000;
450
+ // Takes its context explicitly: the alternate-account flow below records a rejection
451
+ // against A while promoting B, then records B's own outcome. A closure over a single
452
+ // `authCtx` cannot express either.
259
453
  const recordCompactPoolOutcome = (
454
+ ctx: CodexAuthContext,
260
455
  outcome: CodexUpstreamOutcome,
261
- meta: { retryAfter?: string | null; resetAt?: unknown | unknown[] } = {},
456
+ meta: {
457
+ retryAfter?: string | null;
458
+ resetAt?: unknown | unknown[];
459
+ promoteAccountId?: string;
460
+ } = {},
262
461
  ) => {
263
- if (!usesCodexForwardPoolAuth(authCtx, route.provider)) return;
264
- recordCodexUpstreamOutcome(config, authCtx.accountId, outcome, {
462
+ if (!usesCodexForwardPoolAuth(ctx, route.provider)) return;
463
+ recordCodexUpstreamOutcome(config, ctx.accountId, outcome, {
265
464
  ...meta,
266
- threadId: compactThreadId,
465
+ threadId: ctx.kind === "pool" || ctx.kind === "main-pool" ? ctx.affinityKey : undefined,
466
+ fixedAccount: ctx.fixedAccount,
267
467
  modelId: selectedModelId,
268
- probeLeaseId: codexProbeLeaseId(authCtx),
269
- probeQuotaScope: codexProbeQuotaScope(authCtx),
270
- writerGeneration: authCtx.kind === "pool" || authCtx.kind === "main-pool"
271
- ? authCtx.writerGeneration
468
+ probeLeaseId: codexProbeLeaseId(ctx),
469
+ probeQuotaScope: codexProbeQuotaScope(ctx),
470
+ writerGeneration: ctx.kind === "pool" || ctx.kind === "main-pool"
471
+ ? ctx.writerGeneration
272
472
  : undefined,
273
473
  });
274
474
  };
475
+ // Two recovery modes, mirroring retryCodexPoolOnAlternateAccount() on the regular
476
+ // path (core.ts:396). The first account keeps the full ladder — transient-5xx retry
477
+ // wrapping reset retry — because those retries happen before any alternate is even
478
+ // considered. The alternate is one bounded send: a second ladder would multiply the
479
+ // work an already-rejecting pool is doing.
480
+ const sendCompactAttempt = (
481
+ sendProvider: OcxProviderConfig,
482
+ sendHeaders: Headers,
483
+ recovery: "normal" | "single",
484
+ ): Promise<Response> => {
485
+ const doFetch = (upstreamRecovery?: UpstreamSendRecovery) => fetchWithHeaderTimeout(
486
+ compactUrl,
487
+ applyUpstreamRecoveryInit({
488
+ method: "POST",
489
+ headers: sendHeaders,
490
+ body: JSON.stringify({ ...compactBody, model: route.modelId }),
491
+ }, upstreamRecovery),
492
+ req.signal,
493
+ connectMs,
494
+ false,
495
+ providerFetch(sendProvider, undefined, {
496
+ providerName: route.providerName,
497
+ modelId: route.modelId,
498
+ }),
499
+ // Every credential-bearing forward send gets manual redirects, not only
500
+ // pool sends: direct mode carries the caller's credential too (#914).
501
+ sendProvider.authMode === "forward",
502
+ ).then(res => {
503
+ // Every real attempt response — including an intermediate 5xx the retry
504
+ // wrapper replaces — proves the host was reached (#914 review).
505
+ settleObservedCompactHostResponse();
506
+ return res;
507
+ });
508
+ return recovery === "single"
509
+ ? doFetch()
510
+ : fetchWithTransientRetry(doFetch, { abortSignal: req.signal, label: safeHostLabel(compactUrl) });
511
+ };
512
+
513
+ // The account each outcome belongs to. Reassigned only when the alternate send below
514
+ // actually happens, so every recorder call names the context that produced it.
515
+ let outcomeCtx = authCtx;
275
516
  let upstream: Response;
276
517
  try {
277
518
  // Same connect timeout + keep-alive reset + transient-5xx recovery as /v1/responses —
278
519
  // compact hits the same ChatGPT host and must soft-avoid / clear affinity (#186).
279
- upstream = await fetchWithTransientRetry(
280
- recovery => fetchWithHeaderTimeout(
281
- compactUrl,
282
- applyUpstreamRecoveryInit({
283
- method: "POST",
284
- headers,
285
- body: JSON.stringify({ ...compactBody, model: route.modelId }),
286
- }, recovery),
287
- req.signal,
288
- connectMs,
289
- false,
290
- providerFetch(compactProvider),
291
- ),
292
- { abortSignal: req.signal, label: safeHostLabel(compactUrl) },
293
- );
520
+ upstream = await sendCompactAttempt(compactProvider, headers, "normal");
294
521
  } catch (err) {
295
522
  if (req.signal.aborted) {
296
- recordCompactPoolOutcome(499);
523
+ recordCompactPoolOutcome(outcomeCtx, 499);
297
524
  return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
298
525
  }
299
- const outcome = err instanceof Error && err.name === "TimeoutError" ? "timeout" : "connect_error";
300
- recordCompactPoolOutcome(outcome);
526
+ const outcome = classifyTransportFailureKind(err);
527
+ // Host-level evidence stands regardless of pool membership (#914 review).
528
+ if (outcome === "connect_neutral") {
529
+ if (compactHostCircuitEnabled) {
530
+ recordUpstreamHostFailure(actualCompactHostKey, {
531
+ code: transportErrorCode(err),
532
+ threshold: config.upstreamHostCircuitThreshold,
533
+ lease: compactHostAdmissionLease,
534
+ });
535
+ } else {
536
+ recordUpstreamHostFailure(actualCompactHostKey, { code: transportErrorCode(err) });
537
+ }
538
+ } else {
539
+ releaseUpstreamHostAdmission(compactHostAdmissionLease);
540
+ }
541
+ compactHostAdmissionLease = null;
542
+ recordCompactPoolOutcome(outcomeCtx, outcome);
301
543
  return formatErrorResponse(502, "upstream_error", "Failed to connect to compact upstream");
302
544
  }
545
+
546
+ // Bounded same-request alternate: the regular /v1/responses path already does this
547
+ // (core.ts:319-423) and recognizes exactly 429/402. Without it a pool rejection
548
+ // surfaces to the client, which retries the compact task OUTSIDE the logical request
549
+ // — reporting exhausted retries while another pool account sat idle (#913).
550
+ if (
551
+ (upstream.status === 429 || upstream.status === 402)
552
+ && usesCodexForwardPoolAuth(authCtx, route.provider)
553
+ && !authCtx.fixedAccount
554
+ && route.codexAccountMode
555
+ && !req.signal.aborted
556
+ ) {
557
+ const firstRetryAfter = upstream.headers.get("retry-after");
558
+ const firstResetAt = [
559
+ upstream.headers.get("x-codex-primary-reset-at"),
560
+ upstream.headers.get("x-codex-secondary-reset-at"),
561
+ upstream.headers.get("x-codex-tertiary-reset-at"),
562
+ ].filter(Boolean);
563
+ // Build the alternate COMPLETELY before cancelling the first body: if construction
564
+ // throws, the first rejection is still intact and can be returned to the client.
565
+ const alternate = await resolveAlternateCompactContext({
566
+ req,
567
+ config,
568
+ route,
569
+ selectedModelId,
570
+ excludeAccountId: authCtx.accountId,
571
+ turnAdmissionLease,
572
+ });
573
+ // Resolution can await a credential refresh, so the client may have gone away
574
+ // while we were choosing B. Re-check before spending anything: recording A,
575
+ // cancelling its body, and sending B are all observable side effects, and B's
576
+ // quota is not ours to spend on a request nobody is waiting for.
577
+ if (alternate && req.signal.aborted) {
578
+ releaseCodexAuthContextProbeLease(alternate.authCtx);
579
+ recordCompactPoolOutcome(outcomeCtx, 499);
580
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
581
+ }
582
+ if (alternate) {
583
+ // Same order the regular path uses (core.ts:349-357): a 429/402 carries the
584
+ // quota snapshot that produced it, so refresh A's cache before recording its
585
+ // rejection. Skipping this leaves quota-strategy routing and the dashboard
586
+ // reading numbers from before the account ran out.
587
+ if (authCtx.kind === "pool" || authCtx.kind === "main-pool") {
588
+ const { applyAccountQuotaFromUpstreamHeaders } = await import("../../codex/auth-api");
589
+ applyAccountQuotaFromUpstreamHeaders(
590
+ authCtx.accountId,
591
+ upstream.headers,
592
+ authCtx.writerGeneration,
593
+ );
594
+ }
595
+ recordCompactPoolOutcome(authCtx, upstream.status, {
596
+ retryAfter: firstRetryAfter,
597
+ resetAt: firstResetAt,
598
+ ...(alternate.authCtx.accountId ? { promoteAccountId: alternate.authCtx.accountId } : {}),
599
+ });
600
+ await upstream.body?.cancel().catch(() => undefined);
601
+ outcomeCtx = alternate.authCtx;
602
+ logCtx.accountLogLabel = codexAuthContextLogLabel(alternate.authCtx, config);
603
+ try {
604
+ upstream = await sendCompactAttempt(alternate.provider, alternate.headers, "single");
605
+ } catch (err) {
606
+ if (req.signal.aborted) {
607
+ recordCompactPoolOutcome(outcomeCtx, 499);
608
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
609
+ }
610
+ const outcome = classifyTransportFailureKind(err);
611
+ // Host-level evidence stands regardless of pool membership (#914 review).
612
+ if (outcome === "connect_neutral") {
613
+ if (compactHostCircuitEnabled) {
614
+ recordUpstreamHostFailure(actualCompactHostKey, {
615
+ code: transportErrorCode(err),
616
+ threshold: config.upstreamHostCircuitThreshold,
617
+ lease: compactHostAdmissionLease,
618
+ });
619
+ } else {
620
+ recordUpstreamHostFailure(actualCompactHostKey, { code: transportErrorCode(err) });
621
+ }
622
+ } else {
623
+ releaseUpstreamHostAdmission(compactHostAdmissionLease);
624
+ }
625
+ compactHostAdmissionLease = null;
626
+ recordCompactPoolOutcome(outcomeCtx, outcome);
627
+ return formatErrorResponse(502, "upstream_error", "Failed to connect to compact upstream");
628
+ }
629
+ }
630
+ }
303
631
  const retryAfter = upstream.headers.get("retry-after");
304
632
  const resetAt = [
305
633
  upstream.headers.get("x-codex-primary-reset-at"),
@@ -310,13 +638,21 @@ export async function handleResponsesCompact(
310
638
  // Record pool health only after the body is fully delivered (or definitively failed).
311
639
  // A premature 200 would clear soft-avoid while the client still sees a buffer 502.
312
640
  if (buffered.status === 499) {
313
- recordCompactPoolOutcome(499);
641
+ recordCompactPoolOutcome(outcomeCtx, 499);
314
642
  return buffered;
315
643
  }
316
644
  // Always record the real upstream status: a local buffering failure after a
317
645
  // 200 upstream response must not soft-avoid a healthy account or rotate a thread.
318
- recordCompactPoolOutcome(upstream.status, { retryAfter, resetAt });
646
+ recordCompactPoolOutcome(outcomeCtx, upstream.status, { retryAfter, resetAt });
647
+ // Lift usage and response metadata from the buffered upstream JSON into the
648
+ // request log; the routed branch gets the same through handleResponses. The
649
+ // synthetic buffer errors are not upstream bodies and stay uninspected.
650
+ if (buffered.ok) inspectResponseLogJson(logCtx, await buffered.clone().text());
319
651
  return buffered;
652
+ } finally {
653
+ releaseUpstreamHostAdmission(compactHostAdmissionLease);
654
+ releaseCodexAuthContextProbeLease(authCtx);
655
+ }
320
656
  }
321
657
 
322
658
  // ROUTED model: run the v2 synthetic-compaction turn internally (appends COMPACT_PROMPT, no
@@ -324,7 +660,10 @@ export async function handleResponsesCompact(
324
660
  const inputItems = Array.isArray(raw.input) ? (raw.input as unknown[]) : [];
325
661
  const internalBody = {
326
662
  ...raw,
327
- stream: false,
663
+ // Canonical ChatGPT Responses rejects non-streaming turns. Daybreak cannot use the
664
+ // native compact endpoint either, so run its synthetic compaction as SSE and collapse
665
+ // the completed event back into the v1 compact JSON contract below.
666
+ stream: accountGatedCompactWireModel ? true : false,
328
667
  input: [...inputItems, { type: "compaction_trigger" }],
329
668
  };
330
669
  const internalHeaders = new Headers({ "content-type": "application/json" });
@@ -337,13 +676,39 @@ export async function handleResponsesCompact(
337
676
  headers: internalHeaders,
338
677
  body: JSON.stringify(internalBody),
339
678
  });
340
- const response = await handleResponses(internalReq, config, logCtx, { abortSignal: req.signal });
679
+ const response = await handleResponses(internalReq, config, logCtx, { abortSignal: req.signal, turnAdmissionLease, ...(admission ? { admission } : {}) });
341
680
  if (!response.ok) return response;
342
681
  let json: { output?: unknown[]; status?: unknown; error?: unknown };
343
- try {
344
- json = await response.json() as { output?: unknown[]; status?: unknown; error?: unknown };
345
- } catch {
346
- return formatErrorResponse(502, "server_error", "compaction turn returned a non-JSON response");
682
+ if (response.headers.get("content-type")?.includes("text/event-stream")) {
683
+ if (!response.body) {
684
+ return formatErrorResponse(502, "server_error", "compaction turn returned an empty event stream");
685
+ }
686
+ const terminal = { status: "incomplete" as "completed" | "failed" | "incomplete" };
687
+ let completed: { id?: unknown; output?: unknown; status?: unknown } | undefined;
688
+ await new Promise<void>(resolve => {
689
+ consumeForInspection(
690
+ response.body!,
691
+ status => { terminal.status = status; },
692
+ req.signal,
693
+ resolve,
694
+ undefined,
695
+ undefined,
696
+ value => { completed = value; },
697
+ );
698
+ });
699
+ if (req.signal.aborted) {
700
+ return formatErrorResponse(499, "client_cancelled", "Client cancelled compact request");
701
+ }
702
+ if (terminal.status !== "completed" || !completed) {
703
+ return formatErrorResponse(502, "upstream_error", `compaction turn did not complete (status: ${terminal.status})`);
704
+ }
705
+ json = completed as { output?: unknown[]; status?: unknown; error?: unknown };
706
+ } else {
707
+ try {
708
+ json = await response.json() as { output?: unknown[]; status?: unknown; error?: unknown };
709
+ } catch {
710
+ return formatErrorResponse(502, "server_error", "compaction turn returned a non-JSON response");
711
+ }
347
712
  }
348
713
  // The internal turn answers 200 even when it failed or was truncated, so the body
349
714
  // has to be inspected. Reporting a failure beats installing "(no summary
@@ -372,6 +737,13 @@ export async function handleResponsesCompact(
372
737
  `compaction turn produced ${compactionItems.length} compaction items, expected exactly 1`,
373
738
  );
374
739
  }
740
+ // The canonical Responses stream returns a real OpenAI-encrypted compaction item. OCX cannot
741
+ // and should not decrypt it; /responses/compact callers can consume that item directly.
742
+ if (accountGatedCompactWireModel) {
743
+ return new Response(JSON.stringify({ output: compactionItems }), {
744
+ headers: { "Content-Type": "application/json" },
745
+ });
746
+ }
375
747
  const encrypted = compactionItems[0]!.encrypted_content;
376
748
  const decoded = typeof encrypted === "string" ? decodeCompactionSummary(encrypted) : null;
377
749
  // An empty `ocx1:` envelope decodes to "" rather than null, so length is what matters.