@iislee/opencodex 2.11.0 → 2.31.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 (675) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +114 -19
  3. package/bin/ocx.mjs +164 -36
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-BF38heuV.js +104 -0
  6. package/gui/dist/assets/index-DMiI18Kv.css +1 -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 +19 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +376 -52
  44. package/src/adapters/base.ts +54 -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 +601 -0
  48. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  49. package/src/adapters/cursor/cursor-errors.ts +129 -6
  50. package/src/adapters/cursor/discovery.ts +61 -4
  51. package/src/adapters/cursor/effort-map.ts +27 -3
  52. package/src/adapters/cursor/framing.ts +39 -0
  53. package/src/adapters/cursor/h2-pool.ts +123 -0
  54. package/src/adapters/cursor/http1-bidi.ts +361 -0
  55. package/src/adapters/cursor/images.ts +704 -0
  56. package/src/adapters/cursor/live-models.ts +174 -58
  57. package/src/adapters/cursor/live-transport.ts +609 -170
  58. package/src/adapters/cursor/native-exec-common.ts +23 -2
  59. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  60. package/src/adapters/cursor/native-exec-network.ts +1 -1
  61. package/src/adapters/cursor/native-exec-shell.ts +0 -1
  62. package/src/adapters/cursor/native-exec.ts +101 -14
  63. package/src/adapters/cursor/protobuf-events.ts +829 -11
  64. package/src/adapters/cursor/protobuf-request.ts +383 -65
  65. package/src/adapters/cursor/request-builder.ts +237 -31
  66. package/src/adapters/cursor/tool-definitions.ts +242 -12
  67. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  68. package/src/adapters/cursor/transport.ts +22 -0
  69. package/src/adapters/cursor/types.ts +28 -1
  70. package/src/adapters/cursor.ts +133 -7
  71. package/src/adapters/google-antigravity-replay.ts +558 -34
  72. package/src/adapters/google-antigravity-wire.ts +43 -10
  73. package/src/adapters/google-http.ts +38 -10
  74. package/src/adapters/google-tool-schema.ts +80 -15
  75. package/src/adapters/google-truncation.ts +11 -0
  76. package/src/adapters/google.ts +618 -74
  77. package/src/adapters/identity.ts +39 -6
  78. package/src/adapters/kiro-errors.ts +11 -0
  79. package/src/adapters/kiro-events.ts +19 -1
  80. package/src/adapters/kiro-thinking.ts +18 -2
  81. package/src/adapters/kiro-tools.ts +10 -1
  82. package/src/adapters/kiro.ts +92 -54
  83. package/src/adapters/mimo-free.ts +17 -0
  84. package/src/adapters/openai-chat-url.ts +11 -0
  85. package/src/adapters/openai-chat.ts +1311 -336
  86. package/src/adapters/openai-responses-url.ts +16 -0
  87. package/src/adapters/openai-responses.ts +830 -56
  88. package/src/adapters/registry.ts +175 -0
  89. package/src/adapters/responses-tool-schema.ts +67 -0
  90. package/src/adapters/tool-call-id.ts +119 -0
  91. package/src/adapters/tool-catalog-nudge.ts +104 -21
  92. package/src/adapters/xai-web-search.ts +185 -0
  93. package/src/bridge.ts +428 -61
  94. package/src/chat/inbound.ts +43 -19
  95. package/src/chat/outbound.ts +82 -26
  96. package/src/claude/agents-inject.ts +32 -9
  97. package/src/claude/context-windows.ts +21 -5
  98. package/src/claude/desktop-3p.ts +243 -9
  99. package/src/claude/gateway-cache.ts +41 -4
  100. package/src/claude/inbound.ts +72 -3
  101. package/src/claude/model-info.ts +38 -15
  102. package/src/claude/outbound.ts +70 -16
  103. package/src/cli/account-api.ts +35 -1
  104. package/src/cli/account-auth.ts +33 -6
  105. package/src/cli/account-catalog-refresh.ts +14 -0
  106. package/src/cli/account-extended.ts +389 -2
  107. package/src/cli/account-main.ts +317 -0
  108. package/src/cli/account.ts +30 -6
  109. package/src/cli/agent.ts +45 -1
  110. package/src/cli/claude-agent-startup-sync.ts +73 -0
  111. package/src/cli/claude-desktop.ts +29 -4
  112. package/src/cli/claude.ts +103 -34
  113. package/src/cli/codex-log-guard-doctor.ts +103 -0
  114. package/src/cli/codex-shim-autorestore.ts +2 -0
  115. package/src/cli/codex-shim-readiness.ts +76 -0
  116. package/src/cli/combo.ts +8 -0
  117. package/src/cli/config-command.ts +74 -10
  118. package/src/cli/dispatch.ts +593 -0
  119. package/src/cli/doctor.ts +315 -43
  120. package/src/cli/ensure-desired-integrations.ts +152 -0
  121. package/src/cli/export-command.ts +46 -20
  122. package/src/cli/help.ts +20 -271
  123. package/src/cli/index.ts +378 -519
  124. package/src/cli/init.ts +4 -17
  125. package/src/cli/integrations.ts +120 -2
  126. package/src/cli/lab.ts +607 -0
  127. package/src/cli/launcher-context.ts +77 -0
  128. package/src/cli/minimax.ts +497 -0
  129. package/src/cli/models-runtime.ts +35 -2
  130. package/src/cli/models.ts +100 -14
  131. package/src/cli/observe.ts +92 -3
  132. package/src/cli/opencode.ts +4 -2
  133. package/src/cli/provider-runtime.ts +18 -1
  134. package/src/cli/provider.ts +24 -3
  135. package/src/cli/ready.ts +301 -0
  136. package/src/cli/registry.ts +437 -0
  137. package/src/cli/root.ts +86 -0
  138. package/src/cli/route-policy.ts +92 -0
  139. package/src/cli/runtime-api.ts +6 -3
  140. package/src/cli/star-prompt.ts +71 -15
  141. package/src/cli/status.ts +10 -3
  142. package/src/cli/system-restart-client.ts +146 -0
  143. package/src/cli/tray-proxy.ts +153 -6
  144. package/src/cli/v2.ts +105 -10
  145. package/src/cli.ts +1 -1
  146. package/src/clients/config-export.ts +1358 -21
  147. package/src/codex/account-label.ts +14 -1
  148. package/src/codex/account-lifecycle.ts +130 -13
  149. package/src/codex/account-namespaces.ts +49 -3
  150. package/src/codex/account-priority.ts +83 -0
  151. package/src/codex/account-store.ts +29 -2
  152. package/src/codex/account-usability.ts +25 -2
  153. package/src/codex/admission.ts +256 -0
  154. package/src/codex/affinity-debug.ts +162 -0
  155. package/src/codex/app-server-processes.ts +493 -106
  156. package/src/codex/app-server-restart-service.ts +232 -0
  157. package/src/codex/auth-api.ts +849 -242
  158. package/src/codex/auth-collision.ts +5 -3
  159. package/src/codex/auth-context.ts +345 -32
  160. package/src/codex/autostart-health.ts +8 -1
  161. package/src/codex/catalog/account-models.ts +67 -0
  162. package/src/codex/catalog/aggregation.ts +68 -10
  163. package/src/codex/catalog/bundled.ts +331 -33
  164. package/src/codex/catalog/effort.ts +121 -30
  165. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  166. package/src/codex/catalog/kinds.ts +2 -0
  167. package/src/codex/catalog/metadata.ts +529 -45
  168. package/src/codex/catalog/native-models.ts +72 -0
  169. package/src/codex/catalog/parsing.ts +224 -30
  170. package/src/codex/catalog/provider-fetch.ts +1460 -134
  171. package/src/codex/catalog/sync.ts +1449 -186
  172. package/src/codex/catalog-admission.ts +199 -0
  173. package/src/codex/catalog-refresh-status.ts +105 -0
  174. package/src/codex/catalog-write-serialization.ts +242 -0
  175. package/src/codex/catalog.ts +6 -3
  176. package/src/codex/codex-write-lock.ts +384 -0
  177. package/src/codex/convergence-types.ts +614 -0
  178. package/src/codex/convergence.ts +651 -0
  179. package/src/codex/coordinator-doctor.ts +332 -0
  180. package/src/codex/custom-model-catalog-migration.ts +176 -0
  181. package/src/codex/desired-state.ts +230 -0
  182. package/src/codex/features.ts +636 -39
  183. package/src/codex/generation.ts +202 -0
  184. package/src/codex/history-job.ts +407 -0
  185. package/src/codex/history-lock.ts +242 -0
  186. package/src/codex/history-migration-guardian.ts +26 -20
  187. package/src/codex/history-provider.ts +231 -28
  188. package/src/codex/history-transition.ts +105 -0
  189. package/src/codex/history-worker.ts +220 -0
  190. package/src/codex/inject-coordination.ts +290 -0
  191. package/src/codex/inject.ts +1073 -152
  192. package/src/codex/injected-marker.ts +37 -3
  193. package/src/codex/integration-record.ts +266 -0
  194. package/src/codex/internal/catalog-writer.ts +203 -0
  195. package/src/codex/internal/history-writer.ts +80 -0
  196. package/src/codex/journal.ts +66 -4
  197. package/src/codex/log-guard/inspect.ts +506 -0
  198. package/src/codex/log-guard/lock.ts +150 -0
  199. package/src/codex/log-guard/maintenance.ts +403 -0
  200. package/src/codex/log-guard/path-safety.ts +88 -0
  201. package/src/codex/log-guard/policy.ts +44 -0
  202. package/src/codex/log-guard/processes.ts +205 -0
  203. package/src/codex/log-guard/protection.ts +489 -0
  204. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  205. package/src/codex/main-account-cache.ts +24 -0
  206. package/src/codex/main-account.ts +29 -1
  207. package/src/codex/management-convergence.ts +167 -0
  208. package/src/codex/model-cache.ts +56 -10
  209. package/src/codex/model-entitlements.ts +353 -0
  210. package/src/codex/native-main-admission.ts +47 -0
  211. package/src/codex/native-main-auth-temp.ts +187 -0
  212. package/src/codex/native-main-claim.ts +178 -0
  213. package/src/codex/native-main-lock-file.ts +162 -0
  214. package/src/codex/native-main-owner.ts +329 -0
  215. package/src/codex/native-profile-api.ts +247 -0
  216. package/src/codex/native-profile-manager.ts +1531 -0
  217. package/src/codex/native-profile-processes.ts +121 -0
  218. package/src/codex/native-profile-recovery.ts +99 -0
  219. package/src/codex/native-profile-stage-store.ts +387 -0
  220. package/src/codex/native-profile-startup.ts +492 -0
  221. package/src/codex/native-profile-store.ts +855 -0
  222. package/src/codex/native-profile-types.ts +120 -0
  223. package/src/codex/native-residue.ts +682 -0
  224. package/src/codex/paths.ts +80 -1
  225. package/src/codex/plan-from-token.ts +140 -0
  226. package/src/codex/plan.ts +40 -0
  227. package/src/codex/plugins-doctor.ts +1 -1
  228. package/src/codex/pool-rotation.ts +74 -4
  229. package/src/codex/project-config-warnings.ts +20 -6
  230. package/src/codex/prompt-journal.ts +352 -0
  231. package/src/codex/prompt-layers.ts +967 -0
  232. package/src/codex/prompt-lock.ts +143 -0
  233. package/src/codex/quota-rejection.ts +298 -0
  234. package/src/codex/quota.ts +175 -13
  235. package/src/codex/refresh.ts +11 -2
  236. package/src/codex/reset-credit-recovery.ts +1044 -0
  237. package/src/codex/routing.ts +505 -94
  238. package/src/codex/runtime.ts +159 -38
  239. package/src/codex/shim.ts +1009 -28
  240. package/src/codex/subagent-model-fallback.ts +350 -35
  241. package/src/codex/sync.ts +191 -2
  242. package/src/codex/transition-state.ts +612 -0
  243. package/src/codex/upstream-host-health.ts +368 -0
  244. package/src/codex/user-identity.ts +557 -0
  245. package/src/codex/warmup.ts +187 -81
  246. package/src/codex/write-coordination.ts +114 -0
  247. package/src/combos/failover.ts +20 -0
  248. package/src/combos/index.ts +4 -0
  249. package/src/combos/request.ts +32 -0
  250. package/src/combos/types.ts +81 -9
  251. package/src/config/provider-name.ts +24 -0
  252. package/src/config.ts +1762 -140
  253. package/src/generated/compatibility-version.json +3164 -0
  254. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  255. package/src/grok/inject.ts +16 -5
  256. package/src/grok/inspect.ts +45 -0
  257. package/src/grok/sync.ts +2 -2
  258. package/src/images/loop.ts +152 -29
  259. package/src/images/plan.ts +23 -13
  260. package/src/integrations/config-io.ts +269 -0
  261. package/src/integrations/journal.ts +315 -0
  262. package/src/integrations/merge.ts +135 -0
  263. package/src/integrations/mutation-flight.ts +71 -0
  264. package/src/integrations/native/ownership-preflight.ts +202 -0
  265. package/src/integrations/omp-yaml-source.ts +358 -0
  266. package/src/integrations/owned-refresh.ts +74 -0
  267. package/src/integrations/ownership.ts +111 -0
  268. package/src/integrations/registry.ts +159 -0
  269. package/src/integrations/serialize.ts +314 -0
  270. package/src/integrations/state.ts +361 -0
  271. package/src/integrations/store.ts +103 -0
  272. package/src/integrations/writer-lock.ts +98 -0
  273. package/src/integrations/writer.ts +691 -0
  274. package/src/lab/artifacts/sanitize.ts +586 -0
  275. package/src/lab/artifacts/secure-fs.ts +475 -0
  276. package/src/lab/artifacts/store.ts +310 -0
  277. package/src/lab/automation/budgets.ts +78 -0
  278. package/src/lab/automation/config-persistence.ts +256 -0
  279. package/src/lab/automation/constants.ts +39 -0
  280. package/src/lab/automation/cooldown.ts +103 -0
  281. package/src/lab/automation/dispatch.ts +211 -0
  282. package/src/lab/automation/index.ts +13 -0
  283. package/src/lab/automation/orchestrator.ts +499 -0
  284. package/src/lab/automation/persistence.ts +512 -0
  285. package/src/lab/automation/planner.ts +371 -0
  286. package/src/lab/automation/policy.ts +136 -0
  287. package/src/lab/automation/queue.ts +191 -0
  288. package/src/lab/automation/recovery.ts +24 -0
  289. package/src/lab/automation/route-context.ts +21 -0
  290. package/src/lab/automation/run-key.ts +44 -0
  291. package/src/lab/automation/runs-query.ts +34 -0
  292. package/src/lab/automation/types.ts +160 -0
  293. package/src/lab/conformance/assertion.ts +325 -0
  294. package/src/lab/conformance/digest.ts +22 -0
  295. package/src/lab/conformance/executor.ts +741 -0
  296. package/src/lab/conformance/fixture-provider.ts +27 -0
  297. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  298. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  299. package/src/lab/conformance/harness-budget.ts +47 -0
  300. package/src/lab/conformance/index.ts +5 -0
  301. package/src/lab/conformance/jcs.ts +64 -0
  302. package/src/lab/conformance/json-pointer.ts +39 -0
  303. package/src/lab/conformance/manifest.ts +180 -0
  304. package/src/lab/conformance/mcp-stub.ts +179 -0
  305. package/src/lab/conformance/negative-controls.ts +164 -0
  306. package/src/lab/conformance/observation.ts +355 -0
  307. package/src/lab/conformance/runner.ts +68 -0
  308. package/src/lab/conformance/sse-normalize.ts +59 -0
  309. package/src/lab/conformance/suite-manifest.ts +78 -0
  310. package/src/lab/conformance/types.ts +214 -0
  311. package/src/lab/constants.ts +126 -0
  312. package/src/lab/digest.ts +64 -0
  313. package/src/lab/events/errors.ts +9 -0
  314. package/src/lab/events/limits.ts +117 -0
  315. package/src/lab/events/types.ts +229 -0
  316. package/src/lab/events/validate.ts +781 -0
  317. package/src/lab/fabric/constants.ts +40 -0
  318. package/src/lab/fabric/executor.ts +492 -0
  319. package/src/lab/fabric/index.ts +80 -0
  320. package/src/lab/fabric/manifest.ts +222 -0
  321. package/src/lab/fabric/observe.ts +489 -0
  322. package/src/lab/fabric/patch.ts +79 -0
  323. package/src/lab/fabric/producer-child.ts +139 -0
  324. package/src/lab/fabric/producer-isolate.ts +276 -0
  325. package/src/lab/fabric/producer-protocol.ts +61 -0
  326. package/src/lab/fabric/scratch.ts +439 -0
  327. package/src/lab/fabric/subject.ts +106 -0
  328. package/src/lab/fabric/types.ts +134 -0
  329. package/src/lab/fabric/verifier.ts +98 -0
  330. package/src/lab/index.ts +54 -0
  331. package/src/lab/ledger/artifact-refs.ts +127 -0
  332. package/src/lab/ledger/invalidation.ts +136 -0
  333. package/src/lab/ledger/purge.ts +310 -0
  334. package/src/lab/ledger/store.ts +532 -0
  335. package/src/lab/live/credential-lease.ts +53 -0
  336. package/src/lab/live/destination.ts +155 -0
  337. package/src/lab/live/executor.ts +336 -0
  338. package/src/lab/live/inert-tools.ts +56 -0
  339. package/src/lab/live/manifest.ts +85 -0
  340. package/src/lab/live/mcp-loopback.ts +57 -0
  341. package/src/lab/live/runner.ts +19 -0
  342. package/src/lab/live/sandbox.ts +61 -0
  343. package/src/lab/live/suite-manifest.ts +41 -0
  344. package/src/lab/live/transport.ts +118 -0
  345. package/src/lab/live/types.ts +197 -0
  346. package/src/lab/observe/from-conformance.ts +301 -0
  347. package/src/lab/observe/from-live.ts +117 -0
  348. package/src/lab/paths.ts +153 -0
  349. package/src/lab/projection/rebuild.ts +495 -0
  350. package/src/lab/projection/schema.ts +135 -0
  351. package/src/lab/projection/verdicts.ts +474 -0
  352. package/src/lab/projection/verification.ts +412 -0
  353. package/src/lab/public/bundle.ts +217 -0
  354. package/src/lab/public/community-authority.ts +175 -0
  355. package/src/lab/public/community-files.ts +29 -0
  356. package/src/lab/public/community.ts +479 -0
  357. package/src/lab/public/file-safety.ts +155 -0
  358. package/src/lab/public/ids.ts +26 -0
  359. package/src/lab/public/index.ts +16 -0
  360. package/src/lab/public/mutation-lock.ts +424 -0
  361. package/src/lab/public/operator.ts +353 -0
  362. package/src/lab/public/origin-purge.ts +79 -0
  363. package/src/lab/public/origin.ts +203 -0
  364. package/src/lab/public/privacy.ts +143 -0
  365. package/src/lab/public/private-file.ts +261 -0
  366. package/src/lab/public/project.ts +124 -0
  367. package/src/lab/public/purge-test-fault.ts +21 -0
  368. package/src/lab/public/purge.ts +223 -0
  369. package/src/lab/public/registry.ts +44 -0
  370. package/src/lab/public/revocation.ts +252 -0
  371. package/src/lab/public/signature.ts +243 -0
  372. package/src/lab/public/storage.ts +105 -0
  373. package/src/lab/public/strict-json.ts +206 -0
  374. package/src/lab/public/time.ts +26 -0
  375. package/src/lab/public/types.ts +172 -0
  376. package/src/lab/public/validate.ts +391 -0
  377. package/src/lab/query/catalog.ts +101 -0
  378. package/src/lab/query/connection.ts +107 -0
  379. package/src/lab/query/constants.ts +4 -0
  380. package/src/lab/query/cursor.ts +132 -0
  381. package/src/lab/query/dto-map.ts +277 -0
  382. package/src/lab/query/errors.ts +22 -0
  383. package/src/lab/query/freshness.ts +53 -0
  384. package/src/lab/query/index.ts +45 -0
  385. package/src/lab/query/latest-observation.ts +59 -0
  386. package/src/lab/query/passive-production.ts +159 -0
  387. package/src/lab/query/queries.ts +444 -0
  388. package/src/lab/query/types.ts +266 -0
  389. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  390. package/src/lab/subject/installation-salt.ts +112 -0
  391. package/src/lab/subject/protocol-subject.ts +80 -0
  392. package/src/lab/subject/route-subject.ts +74 -0
  393. package/src/lib/app-owned-memory-stores.ts +22 -0
  394. package/src/lib/bounded-body.ts +153 -9
  395. package/src/lib/bun-runtime.ts +125 -12
  396. package/src/lib/bun-stream-caps.ts +13 -9
  397. package/src/lib/codex-restart-contract.ts +120 -0
  398. package/src/lib/config-ownership.ts +6 -2
  399. package/src/lib/destination-policy.ts +65 -1
  400. package/src/lib/errors.ts +44 -2
  401. package/src/lib/fabric-task-execution-authority.ts +7 -0
  402. package/src/lib/fabric-task-host.ts +29 -0
  403. package/src/lib/lab-activation.ts +223 -0
  404. package/src/lib/lab-live-execution-authority.ts +13 -0
  405. package/src/lib/lab-live-host.ts +30 -0
  406. package/src/lib/lab-live-pinned-sender.ts +56 -0
  407. package/src/lib/lab-live-route-production.ts +130 -0
  408. package/src/lib/lab-passive-linker-registration.ts +26 -0
  409. package/src/lib/local-management-attestation.ts +51 -0
  410. package/src/lib/local-management-capability.ts +100 -0
  411. package/src/lib/local-provider-reload-contract.ts +100 -0
  412. package/src/lib/optional-shutdown-hooks.ts +57 -0
  413. package/src/lib/pinned-http.ts +145 -26
  414. package/src/lib/process-control.ts +4 -1
  415. package/src/lib/provider-outbound.ts +49 -9
  416. package/src/lib/redact.ts +419 -3
  417. package/src/lib/self-launch-argv.ts +15 -0
  418. package/src/lib/server-resource-ownership.ts +71 -0
  419. package/src/lib/shadow-call.ts +35 -4
  420. package/src/lib/sse-decoder.ts +41 -0
  421. package/src/lib/state-store-registrations.ts +10 -2
  422. package/src/lib/system-restart-contract.ts +73 -0
  423. package/src/lib/token-estimate.ts +19 -2
  424. package/src/lib/tool-argument-integers.ts +202 -0
  425. package/src/lib/translator-budget.ts +44 -0
  426. package/src/lib/upstream-http-version.ts +57 -0
  427. package/src/lib/upstream-reachability.ts +95 -0
  428. package/src/lib/upstream-retry.ts +156 -3
  429. package/src/lib/windows-atomic-replace.ts +155 -0
  430. package/src/lib/windows-elevation.ts +70 -2
  431. package/src/lib/windows-secret-acl.ts +409 -69
  432. package/src/lib/windows-service-wrappers.ts +72 -0
  433. package/src/lib/windows-text.ts +106 -0
  434. package/src/lib/windows-user-principal.ts +341 -0
  435. package/src/lib/winsw.ts +33 -5
  436. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  437. package/src/oauth/account-import/index.ts +15 -0
  438. package/src/oauth/account-import/parser.ts +83 -0
  439. package/src/oauth/account-import/registry.ts +18 -0
  440. package/src/oauth/account-import/service.ts +75 -0
  441. package/src/oauth/account-import/types.ts +91 -0
  442. package/src/oauth/anthropic.ts +12 -1
  443. package/src/oauth/callback-server.ts +8 -2
  444. package/src/oauth/chatgpt.ts +12 -1
  445. package/src/oauth/command-code.ts +239 -0
  446. package/src/oauth/cursor.ts +46 -5
  447. package/src/oauth/google-antigravity.ts +35 -3
  448. package/src/oauth/health.ts +20 -12
  449. package/src/oauth/index.ts +398 -66
  450. package/src/oauth/key-providers.ts +16 -0
  451. package/src/oauth/kimi.ts +16 -2
  452. package/src/oauth/kiro.ts +50 -6
  453. package/src/oauth/local-token-detect.ts +11 -2
  454. package/src/oauth/log.ts +3 -1
  455. package/src/oauth/login-cli.ts +88 -28
  456. package/src/oauth/nous.ts +798 -0
  457. package/src/oauth/store.ts +119 -21
  458. package/src/oauth/token-guardian.ts +9 -3
  459. package/src/pi/models.ts +2 -2
  460. package/src/providers/alibaba-region-migration.ts +1 -1
  461. package/src/providers/antigravity-models.ts +521 -31
  462. package/src/providers/base-url-choices.ts +10 -0
  463. package/src/providers/codex-capacity.ts +292 -0
  464. package/src/providers/command-code-efforts.ts +144 -0
  465. package/src/providers/context-cap.ts +22 -5
  466. package/src/providers/cursor-pool.ts +72 -0
  467. package/src/providers/derive.ts +253 -6
  468. package/src/providers/fastwire.ts +501 -0
  469. package/src/providers/free-directory.ts +10 -7
  470. package/src/providers/google-vertex-location.ts +14 -0
  471. package/src/providers/key-failover.ts +71 -3
  472. package/src/providers/label.ts +1 -1
  473. package/src/providers/model-discovery-limits.ts +16 -0
  474. package/src/providers/model-discovery.ts +115 -22
  475. package/src/providers/model-rename-migration.ts +255 -0
  476. package/src/providers/model-rename-startup.ts +28 -0
  477. package/src/providers/openai-sidecar.ts +72 -4
  478. package/src/providers/openai-tier-startup.ts +31 -2
  479. package/src/providers/openai-tiers.ts +119 -4
  480. package/src/providers/openai-virtual-models.ts +1 -0
  481. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  482. package/src/providers/provider-id-rewrite.ts +29 -0
  483. package/src/providers/quota.ts +1319 -38
  484. package/src/providers/registry.ts +1429 -111
  485. package/src/providers/request-pacing.ts +310 -0
  486. package/src/providers/service-tier.ts +277 -0
  487. package/src/providers/slug-codec.ts +42 -6
  488. package/src/providers/static-model-discovery.ts +86 -0
  489. package/src/providers/xai-responses-opt-in.ts +15 -0
  490. package/src/providers/xai-transport.ts +11 -4
  491. package/src/reasoning-effort.ts +49 -1
  492. package/src/responses/compaction.ts +26 -1
  493. package/src/responses/custom-tool-compat.ts +266 -0
  494. package/src/responses/hosted-tool-policy.ts +9 -0
  495. package/src/responses/namespace-tool-compat.ts +355 -0
  496. package/src/responses/parser.ts +220 -38
  497. package/src/responses/provider-continuation.ts +98 -0
  498. package/src/responses/provider-opaque-metadata.ts +73 -0
  499. package/src/responses/reasoning-envelope.ts +9 -1
  500. package/src/responses/reasoning-replay-cache.ts +426 -0
  501. package/src/responses/schema.ts +7 -1
  502. package/src/responses/spill-store.ts +75 -10
  503. package/src/responses/state.ts +565 -27
  504. package/src/responses/thought-signature-replay.ts +347 -0
  505. package/src/responses/tool-search-compat.ts +301 -0
  506. package/src/responses/truncated-stop-reason.ts +60 -0
  507. package/src/router.ts +366 -30
  508. package/src/routing/analytics.ts +378 -0
  509. package/src/routing/capability.ts +244 -0
  510. package/src/routing/compatibility/assemble.ts +73 -0
  511. package/src/routing/compatibility/behavior.ts +278 -0
  512. package/src/routing/compatibility/catalog.ts +99 -0
  513. package/src/routing/compatibility/endpoint.ts +52 -0
  514. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  515. package/src/routing/compatibility/policy.ts +181 -0
  516. package/src/routing/compatibility/provider-slot.ts +56 -0
  517. package/src/routing/compatibility/reader.ts +110 -0
  518. package/src/routing/compatibility/subject.ts +191 -0
  519. package/src/routing/compatibility/types.ts +64 -0
  520. package/src/routing/compatibility/version.ts +104 -0
  521. package/src/routing/cost.ts +77 -0
  522. package/src/routing/evaluator.ts +495 -0
  523. package/src/routing/health.ts +412 -0
  524. package/src/routing/history/cursor.ts +43 -0
  525. package/src/routing/history/indexer.ts +605 -0
  526. package/src/routing/history/schema.ts +72 -0
  527. package/src/routing/profile-namespace.ts +15 -0
  528. package/src/routing/profile.ts +547 -0
  529. package/src/routing/quota.ts +145 -0
  530. package/src/routing/request-evidence.ts +45 -0
  531. package/src/routing/trace.ts +776 -0
  532. package/src/server/adapter-resolve.ts +2 -29
  533. package/src/server/auth-cors.ts +267 -46
  534. package/src/server/background-lifecycle.ts +182 -0
  535. package/src/server/chat-completions.ts +130 -56
  536. package/src/server/chat-native-sse.ts +331 -0
  537. package/src/server/chat-native.ts +426 -0
  538. package/src/server/claude-messages.ts +159 -43
  539. package/src/server/direct-local-http.ts +347 -0
  540. package/src/server/effort-policy.ts +18 -0
  541. package/src/server/github-copilot-responses-repair.ts +338 -0
  542. package/src/server/gui-static.ts +39 -10
  543. package/src/server/images.ts +94 -12
  544. package/src/server/index.ts +865 -181
  545. package/src/server/lifecycle.ts +284 -13
  546. package/src/server/live.ts +136 -17
  547. package/src/server/local-management-read-client.ts +90 -0
  548. package/src/server/local-provider-reload-client.ts +137 -0
  549. package/src/server/management/agent-settings-routes.ts +398 -103
  550. package/src/server/management/api-key-usage.ts +31 -5
  551. package/src/server/management/body.ts +6 -0
  552. package/src/server/management/combo-routes.ts +62 -24
  553. package/src/server/management/config-routes.ts +464 -51
  554. package/src/server/management/context.ts +80 -2
  555. package/src/server/management/integration-routes.ts +498 -0
  556. package/src/server/management/lab-automation-routes.ts +206 -0
  557. package/src/server/management/lab-routes.ts +563 -0
  558. package/src/server/management/logs-usage-routes.ts +101 -32
  559. package/src/server/management/model-routes.ts +189 -131
  560. package/src/server/management/model-rows.ts +163 -0
  561. package/src/server/management/native-integration-routes.ts +769 -0
  562. package/src/server/management/oauth-account-routes.ts +80 -4
  563. package/src/server/management/provider-capability-config.ts +48 -0
  564. package/src/server/management/provider-routes.ts +764 -157
  565. package/src/server/management/request-history-routes.ts +191 -0
  566. package/src/server/management/routing-analytics-routes.ts +74 -0
  567. package/src/server/management/routing-profile-routes.ts +380 -0
  568. package/src/server/management/shared.ts +27 -11
  569. package/src/server/management/sidebar-routes.ts +47 -31
  570. package/src/server/management/storage-log-guard-routes.ts +186 -0
  571. package/src/server/management/sync-response.ts +69 -0
  572. package/src/server/management/system-restart.ts +288 -32
  573. package/src/server/management/system-routes.ts +77 -0
  574. package/src/server/management/usage-summary-cache.ts +9 -1
  575. package/src/server/management/vision-sidecar-options.ts +167 -0
  576. package/src/server/management/web-search-sidecar-options.ts +120 -0
  577. package/src/server/management-api.ts +115 -14
  578. package/src/server/management-auth.ts +220 -5
  579. package/src/server/passive-route-linker.ts +66 -0
  580. package/src/server/ports.ts +41 -1
  581. package/src/server/proxy-liveness.ts +132 -5
  582. package/src/server/readiness.ts +99 -0
  583. package/src/server/relay-eager.ts +82 -42
  584. package/src/server/relay.ts +236 -76
  585. package/src/server/request-decompress.ts +113 -6
  586. package/src/server/request-log.ts +235 -22
  587. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  588. package/src/server/responses/agent-task-recovery.ts +465 -0
  589. package/src/server/responses/collaboration.ts +204 -35
  590. package/src/server/responses/compact.ts +442 -55
  591. package/src/server/responses/core.ts +2872 -331
  592. package/src/server/responses/empty-completion-guard.ts +276 -0
  593. package/src/server/responses/encrypted-payload.ts +62 -39
  594. package/src/server/responses/fetch-helpers.ts +79 -4
  595. package/src/server/responses/input-admission.ts +185 -0
  596. package/src/server/responses/pacing-overload.ts +13 -0
  597. package/src/server/responses/policy-fallback.ts +178 -0
  598. package/src/server/responses/responses-field-backfill.ts +251 -0
  599. package/src/server/responses/terminal-guard.ts +26 -5
  600. package/src/server/responses/upstream-error.ts +5 -0
  601. package/src/server/responses/ws-upstream.ts +308 -0
  602. package/src/server/responses-custom-tool-repair.ts +282 -0
  603. package/src/server/responses-item-id-repair.ts +54 -6
  604. package/src/server/responses-json-events.ts +90 -0
  605. package/src/server/responses-model-rewrite.ts +29 -0
  606. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  607. package/src/server/responses-snapshot-repair.ts +621 -0
  608. package/src/server/responses-terminal-repair.ts +342 -0
  609. package/src/server/responses-tool-search-repair.ts +267 -0
  610. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  611. package/src/server/responses.ts +18 -2
  612. package/src/server/search.ts +78 -13
  613. package/src/server/sse-frame-buffer.ts +292 -0
  614. package/src/server/sse-payload-rewrite.ts +110 -22
  615. package/src/server/startup-action-control.ts +8 -1
  616. package/src/server/startup-health-cache.ts +19 -1
  617. package/src/server/system-env.ts +80 -9
  618. package/src/server/ws-bridge.ts +39 -38
  619. package/src/service-manager-probe.ts +892 -0
  620. package/src/service.ts +1111 -90
  621. package/src/sidecar/auth.ts +92 -0
  622. package/src/sidecar/candidates.ts +83 -0
  623. package/src/storage/cleanup.ts +2 -2
  624. package/src/storage/scanner.ts +1 -1
  625. package/src/storage/worker-lifecycle.ts +14 -14
  626. package/src/tray/windows-tray.ps1 +83 -9
  627. package/src/tray/windows.ts +43 -16
  628. package/src/types/accounts.ts +37 -0
  629. package/src/types/config.ts +845 -0
  630. package/src/types/provider.ts +545 -0
  631. package/src/types/request.ts +384 -0
  632. package/src/types/tools.ts +131 -0
  633. package/src/types/wire.ts +80 -0
  634. package/src/types.ts +104 -1236
  635. package/src/update/index.ts +32 -19
  636. package/src/update/job.ts +442 -67
  637. package/src/update/notify.ts +12 -6
  638. package/src/update/npm-cache-preflight.d.mts +47 -0
  639. package/src/update/npm-cache-preflight.mjs +201 -0
  640. package/src/update/transactional-install.d.mts +22 -0
  641. package/src/update/transactional-install.mjs +259 -0
  642. package/src/usage/cost.ts +0 -0
  643. package/src/usage/expected-prices.ts +268 -16
  644. package/src/usage/log.ts +606 -41
  645. package/src/usage/summary.ts +177 -9
  646. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  647. package/src/usage/user-cost-overlays.ts +314 -0
  648. package/src/vision/anthropic-describe.ts +10 -6
  649. package/src/vision/backends.ts +97 -0
  650. package/src/vision/describe.ts +9 -3
  651. package/src/vision/eligibility.ts +250 -0
  652. package/src/vision/index.ts +238 -24
  653. package/src/vision/reasoning.ts +55 -0
  654. package/src/vision/routed-describe.ts +175 -0
  655. package/src/vision/timeout-bounds.ts +9 -0
  656. package/src/web-search/anthropic-executor.ts +13 -7
  657. package/src/web-search/backends.ts +108 -0
  658. package/src/web-search/exa-executor.ts +88 -0
  659. package/src/web-search/executor.ts +11 -3
  660. package/src/web-search/gemini-executor.ts +141 -0
  661. package/src/web-search/index.ts +150 -15
  662. package/src/web-search/loop.ts +279 -50
  663. package/src/web-search/parse.ts +125 -30
  664. package/src/web-search/sources.ts +60 -0
  665. package/src/web-search/xai-executor.ts +219 -0
  666. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  667. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  668. package/gui/dist/provider-icons/antigravity.svg +0 -1
  669. package/gui/dist/provider-icons/claude.svg +0 -1
  670. package/gui/dist/provider-icons/copilot.svg +0 -1
  671. package/gui/dist/provider-icons/cursor.svg +0 -2
  672. package/gui/dist/provider-icons/gemini.svg +0 -1
  673. package/gui/dist/provider-icons/grok-color.svg +0 -1
  674. package/gui/dist/provider-icons/kiro.svg +0 -14
  675. package/src/cli/internal-dispatch.ts +0 -20
@@ -0,0 +1,153 @@
1
+ import { namespacedToolName } from "../types";
2
+ import { sseDataPayload, type SseBlockRewrite } from "./sse-payload-rewrite";
3
+
4
+ /**
5
+ * Item types the CLIENT executes by name. Hosted calls (`web_search_call`,
6
+ * `image_generation_call`, `local_shell_call`, `tool_search_call`, …) are run upstream or
7
+ * carry no tool name, so they are never matched against the request catalog.
8
+ */
9
+ const CLIENT_EXECUTED_CALL_TYPES = new Set(["function_call", "custom_tool_call"]);
10
+
11
+ /** An upstream-supplied name reaches the error message; keep it bounded. */
12
+ const MAX_REPORTED_NAME_CHARS = 100;
13
+
14
+ export const UNDECLARED_TOOL_CALL_ERROR_CODE = "undeclared_tool_call";
15
+
16
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
17
+ return !!value && typeof value === "object" && !Array.isArray(value);
18
+ }
19
+
20
+ function addWireToolName(names: Set<string>, tool: unknown, namespace?: string): void {
21
+ if (!isPlainObject(tool) || typeof tool.name !== "string" || tool.name.length === 0) return;
22
+ names.add(tool.name);
23
+ // Codex routes MCP calls by an explicit `namespace` field, so the same tool is reachable
24
+ // as a bare inner name or as the flattened form; accept both rather than guess which
25
+ // coordinate system this provider echoes back.
26
+ if (namespace) names.add(namespacedToolName(namespace, tool.name));
27
+ }
28
+
29
+ function addWireToolSpecs(names: Set<string>, specs: unknown): void {
30
+ if (!Array.isArray(specs)) return;
31
+ for (const spec of specs) {
32
+ if (!isPlainObject(spec)) continue;
33
+ if (spec.type === "namespace" && Array.isArray(spec.tools)) {
34
+ const namespace = typeof spec.name === "string" ? spec.name : undefined;
35
+ for (const inner of spec.tools) addWireToolName(names, inner, namespace);
36
+ continue;
37
+ }
38
+ addWireToolName(names, spec);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Tool names the OUTBOUND Responses body actually declared.
44
+ *
45
+ * This reads the body that goes upstream rather than the parsed internal tool list: the
46
+ * passthrough forwards wire shapes (namespaced MCP groups, `additional_tools` items carried
47
+ * inside `input`, routed custom-tool rewrites) that the internal list flattens or renames, and
48
+ * only the wire names can be compared against what the provider echoes back.
49
+ */
50
+ export function collectDeclaredWireToolNames(body: unknown): Set<string> {
51
+ const names = new Set<string>();
52
+ if (!isPlainObject(body)) return names;
53
+ addWireToolSpecs(names, body.tools);
54
+ if (Array.isArray(body.input)) {
55
+ for (const item of body.input) {
56
+ if (isPlainObject(item) && item.type === "additional_tools") addWireToolSpecs(names, item.tools);
57
+ }
58
+ }
59
+ return names;
60
+ }
61
+
62
+ function undeclaredNameInItem(item: unknown, declared: ReadonlySet<string>): string | undefined {
63
+ if (!isPlainObject(item)) return undefined;
64
+ if (typeof item.type !== "string" || !CLIENT_EXECUTED_CALL_TYPES.has(item.type)) return undefined;
65
+ const name = item.name;
66
+ if (typeof name !== "string" || name.length === 0) return undefined;
67
+ if (declared.has(name)) return undefined;
68
+ if (typeof item.namespace === "string" && declared.has(namespacedToolName(item.namespace, name))) {
69
+ return undefined;
70
+ }
71
+ return name;
72
+ }
73
+
74
+ /** First undeclared client tool named by a Responses SSE payload, or undefined. */
75
+ export function undeclaredToolCallName(
76
+ payload: unknown,
77
+ declared: ReadonlySet<string>,
78
+ ): string | undefined {
79
+ if (!isPlainObject(payload)) return undefined;
80
+ if (payload.type === "response.output_item.added" || payload.type === "response.output_item.done") {
81
+ return undeclaredNameInItem(payload.item, declared);
82
+ }
83
+ // Sparse gateways skip incremental items and only ever ship the terminal snapshot.
84
+ if (payload.type === "response.completed" || payload.type === "response.incomplete") {
85
+ return undeclaredToolCallNameInResponse(payload.response, declared);
86
+ }
87
+ return undefined;
88
+ }
89
+
90
+ /** First undeclared client tool in a Responses object's `output` array, or undefined. */
91
+ export function undeclaredToolCallNameInResponse(
92
+ response: unknown,
93
+ declared: ReadonlySet<string>,
94
+ ): string | undefined {
95
+ if (!isPlainObject(response) || !Array.isArray(response.output)) return undefined;
96
+ for (const item of response.output) {
97
+ const name = undeclaredNameInItem(item, declared);
98
+ if (name !== undefined) return name;
99
+ }
100
+ return undefined;
101
+ }
102
+
103
+ export function undeclaredToolCallMessage(name: string): string {
104
+ const reported = name.slice(0, MAX_REPORTED_NAME_CHARS);
105
+ return `routed provider emitted undeclared client tool "${reported}"; only request-declared tools may be called`;
106
+ }
107
+
108
+ function failedBlocks(name: string, newline: string): readonly string[] {
109
+ const failure = {
110
+ type: "upstream_error",
111
+ code: UNDECLARED_TOOL_CALL_ERROR_CODE,
112
+ message: undeclaredToolCallMessage(name),
113
+ };
114
+ const payload = JSON.stringify({
115
+ type: "response.failed",
116
+ response: { status: "failed", error: failure, last_error: failure },
117
+ });
118
+ return [`event: response.failed${newline}data: ${payload}`, "data: [DONE]"];
119
+ }
120
+
121
+ /**
122
+ * Fail closed when a routed provider calls a tool the request never declared (#1700).
123
+ *
124
+ * The bridged paths already refuse such a call (`declaredToolNames` in src/bridge.ts), but the
125
+ * native Responses passthrough relayed it verbatim: Codex received a `function_call` for a tool
126
+ * it has no top-level handler for — `apply_patch`, which under code mode exists only as a nested
127
+ * `tools.apply_patch(...)` helper inside `exec` — and the turn surfaced as a bare `aborted` with
128
+ * no output and no explanation. Replacing the offending event with an explicit `response.failed`
129
+ * turns that silent dead end into a compatibility error naming the tool.
130
+ *
131
+ * Everything after the trip is dropped so a later `response.completed` cannot contradict the
132
+ * terminal already sent. Non-JSON and non-item blocks pass through untouched.
133
+ */
134
+ export function createUndeclaredToolCallGuardBlockRewrite(
135
+ declared: ReadonlySet<string>,
136
+ ): SseBlockRewrite {
137
+ let tripped = false;
138
+ return (block: string) => {
139
+ if (tripped) return [];
140
+ const payload = sseDataPayload(block);
141
+ if (payload === null || payload === "[DONE]") return [block];
142
+ let parsed: unknown;
143
+ try {
144
+ parsed = JSON.parse(payload);
145
+ } catch {
146
+ return [block];
147
+ }
148
+ const name = undeclaredToolCallName(parsed, declared);
149
+ if (name === undefined) return [block];
150
+ tripped = true;
151
+ return failedBlocks(name, block.includes("\r\n") ? "\r\n" : "\n");
152
+ };
153
+ }
@@ -1,9 +1,25 @@
1
1
  // AUTO-SPLIT facade: original responses.ts body moved into ./responses/* modules.
2
2
  // Public surface preserved exactly; importers keep using "src/server/responses".
3
+ import { handleResponsesCompact as handleResponsesCompactImpl } from "./responses/compact";
4
+ import { requestPacingOverloadResponse } from "./responses/pacing-overload";
5
+
3
6
  export { buildToolBridgeMaps, isV1CollabSurface, collabSurface, multiAgentGuidanceText, V2_GUIDANCE_CHAR_BUDGET, injectDeveloperMessage } from "./responses/collaboration";
4
7
  export type { MultiAgentGuidanceOptions, MultiAgentGuidanceDeps } from "./responses/collaboration";
5
8
  export { hasUnreadableEncryptedAgentTask, sanitizeEncryptedContentInPlace } from "./responses/encrypted-payload";
6
- export { COMPACT_RESPONSE_MAX_BYTES, bufferCompactResponse, handleResponsesCompact } from "./responses/compact";
9
+ export { COMPACT_RESPONSE_MAX_BYTES, bufferCompactResponse } from "./responses/compact";
7
10
  export { disableResponsesRequestTimeout, safeHostLabel, fetchWithHeaderTimeout } from "./responses/fetch-helpers";
8
- export { sidecarOutcomeRecorder, isShadowSourceModel, codexLogAccountId, usesCodexForwardPoolAuth, codexForwardTerminalOutcomeRecorder, decodeRequestErrorResponse, buildComboChildHeaders, handleResponses, linkAbortSignal } from "./responses/core";
11
+ export { sidecarOutcomeRecorder, isShadowSourceModel, codexLogAccountId, usesCodexForwardPoolAuth, codexForwardTerminalOutcomeRecorder, decodeRequestErrorResponse, buildComboChildHeaders, linkAbortSignal } from "./responses/core";
12
+ export { handleResponses, handleResponsesWithPolicyFallback, rankPolicyFallbackCandidates } from "./responses/policy-fallback";
9
13
  export { adapterNeedsForcedContinuation } from "./responses/core";
14
+
15
+ export async function handleResponsesCompact(
16
+ ...args: Parameters<typeof handleResponsesCompactImpl>
17
+ ): Promise<Response> {
18
+ try {
19
+ return await handleResponsesCompactImpl(...args);
20
+ } catch (error) {
21
+ const overload = requestPacingOverloadResponse(error);
22
+ if (overload) return overload;
23
+ throw error;
24
+ }
25
+ }
@@ -11,20 +11,31 @@
11
11
  import { formatErrorResponse } from "../bridge";
12
12
  import {
13
13
  CodexAccountCooldownError,
14
+ codexMainProfileDrainingResponse,
14
15
  cooldownErrorResponse,
15
16
  CodexAuthContextError,
17
+ CodexMainProfileDrainingError,
16
18
  CodexPoolAuthenticationError,
17
19
  CodexThreadAffinityExpiredError,
18
20
  } from "../codex/auth-context";
21
+ import { codexAccountNamespaceForModel } from "../codex/account-namespace-match";
19
22
  import { formatCodexProviderForLog } from "../codex/routing";
20
23
  import { signalWithTimeout } from "../lib/abort";
24
+ import { readBoundedResponseBytes } from "../lib/bounded-body";
21
25
  import { sidecarEnter } from "../lib/sidecar-tracker";
22
26
  import type { OcxConfig } from "../types";
23
- import { listOpenAiForwardSidecarCandidates, resolveFirstUsableOpenAiSidecar } from "../providers/openai-sidecar";
27
+ import {
28
+ listOpenAiForwardSidecarCandidates,
29
+ resolveFirstUsableOpenAiSidecar,
30
+ type ExactOpenAiSidecarAccount,
31
+ } from "../providers/openai-sidecar";
32
+ import { routeModel } from "../router";
24
33
  import { readJsonRequestBody } from "./request-decompress";
25
34
  import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "./auth-cors";
26
35
  import type { RequestLogContext } from "./request-log";
27
36
  import { codexLogAccountId, decodeRequestErrorResponse } from "./responses";
37
+ import type { AdmissionLease } from "../lib/admission";
38
+ import { codexAccountSelectionForTurn } from "./lifecycle";
28
39
 
29
40
  /**
30
41
  * Default TOTAL deadline for one search relay. alpha/search is non-streaming JSON — response
@@ -34,12 +45,13 @@ import { codexLogAccountId, decodeRequestErrorResponse } from "./responses";
34
45
  * long-running search).
35
46
  */
36
47
  const SEARCH_UPSTREAM_TIMEOUT_MS = 200_000;
37
- const SEARCH_RESPONSE_MAX_BYTES = 16 * 1024 * 1024;
48
+ export const SEARCH_RESPONSE_MAX_BYTES = 16 * 1024 * 1024;
38
49
 
39
50
  export async function handleSearch(
40
51
  req: Request,
41
52
  config: OcxConfig,
42
53
  logCtx: RequestLogContext,
54
+ turnAdmissionLease?: AdmissionLease,
43
55
  ): Promise<Response> {
44
56
  try { validateForwardAdmissionCredential(req.headers, config); }
45
57
  catch (err) {
@@ -55,6 +67,32 @@ export async function handleSearch(
55
67
  const model = (body as { model?: unknown } | null)?.model;
56
68
  if (typeof model === "string" && model) logCtx.model = model;
57
69
 
70
+ let exactAccount: ExactOpenAiSidecarAccount | undefined;
71
+ let relayBody = body;
72
+ const accountNamespace = typeof model === "string"
73
+ ? codexAccountNamespaceForModel(config.codexAccountNamespaces, model)
74
+ : undefined;
75
+ if (accountNamespace && typeof model === "string") {
76
+ try {
77
+ const route = routeModel(config, model);
78
+ if (!route.codexAccountId || route.codexAccountNamespace !== accountNamespace) {
79
+ return formatErrorResponse(400, "invalid_request_error", "Invalid Codex account-qualified search model");
80
+ }
81
+ exactAccount = { accountId: route.codexAccountId, modelId: route.modelId };
82
+ logCtx.provider = `${route.providerName}-${accountNamespace}`;
83
+ logCtx.routeDecision = route.routeDecision;
84
+ // The ChatGPT search endpoint only understands the native model slug. The
85
+ // account namespace is proxy routing syntax and must not cross the wire.
86
+ relayBody = { ...(body as Record<string, unknown>), model: route.modelId };
87
+ } catch (err) {
88
+ return formatErrorResponse(
89
+ 400,
90
+ "invalid_request_error",
91
+ err instanceof Error ? err.message : "Invalid Codex account-qualified search model",
92
+ );
93
+ }
94
+ }
95
+
58
96
  const candidates = listOpenAiForwardSidecarCandidates(config);
59
97
  if (candidates.length === 0) {
60
98
  return formatErrorResponse(
@@ -67,7 +105,10 @@ export async function handleSearch(
67
105
 
68
106
  let upstream: Awaited<ReturnType<typeof resolveFirstUsableOpenAiSidecar>>;
69
107
  try {
70
- upstream = await resolveFirstUsableOpenAiSidecar(candidates, req.headers, config);
108
+ upstream = await resolveFirstUsableOpenAiSidecar(candidates, req.headers, config, {
109
+ exactAccount,
110
+ beginCodexAccountSelection: codexAccountSelectionForTurn(turnAdmissionLease),
111
+ });
71
112
  if (!upstream) {
72
113
  return formatErrorResponse(
73
114
  401,
@@ -75,16 +116,21 @@ export async function handleSearch(
75
116
  "web search relay needs ChatGPT auth (Authorization header)",
76
117
  );
77
118
  }
78
- logCtx.provider = formatCodexProviderForLog(upstream.providerName, codexLogAccountId(upstream.authContext), config);
119
+ logCtx.provider = accountNamespace
120
+ ? `${upstream.providerName}-${accountNamespace}`
121
+ : formatCodexProviderForLog(upstream.providerName, codexLogAccountId(upstream.authContext), config);
79
122
  } catch (err) {
80
123
  if (err instanceof CodexAccountCooldownError) {
81
- return cooldownErrorResponse(err);
124
+ return cooldownErrorResponse(err, Date.now(), accountNamespace);
82
125
  }
126
+ if (err instanceof CodexMainProfileDrainingError) return codexMainProfileDrainingResponse();
83
127
  if (err instanceof CodexThreadAffinityExpiredError) {
84
128
  return formatErrorResponse(409, "invalid_request_error", "Codex thread account affinity expired; start a new session");
85
129
  }
86
130
  if (err instanceof CodexAuthContextError) {
87
- const safeAccountLabel = formatCodexProviderForLog("openai", err.accountId, config);
131
+ const safeAccountLabel = accountNamespace
132
+ ? `openai-${accountNamespace}`
133
+ : formatCodexProviderForLog("openai", err.accountId, config);
88
134
  console.error(`[search] Pool account ${safeAccountLabel} token failed; reauthentication required`);
89
135
  return formatErrorResponse(401, "authentication_error", "Selected Codex account needs reauthentication");
90
136
  }
@@ -99,27 +145,40 @@ export async function handleSearch(
99
145
  const timeoutMs = config.search?.timeoutMs ?? SEARCH_UPSTREAM_TIMEOUT_MS;
100
146
  const linkedSignal = signalWithTimeout(timeoutMs, req.signal);
101
147
  const sidecarExit = sidecarEnter("search");
148
+ let upstreamResponse: Response | undefined;
102
149
  try {
103
- const upstreamResponse = await fetch(url, {
150
+ upstreamResponse = await fetch(url, {
104
151
  method: "POST",
105
152
  headers,
106
- body: JSON.stringify(body),
153
+ body: JSON.stringify(relayBody),
154
+ signal: linkedSignal.signal,
155
+ // Credential-bearing: do not follow a cross-origin 3xx. Bun strips `Authorization`
156
+ // across origins but forwards nonstandard headers such as `chatgpt-account-id`,
157
+ // `session_id`, and `x-codex-turn-metadata` to the redirect target.
158
+ redirect: "manual",
159
+ });
160
+ const observed = await readBoundedResponseBytes(upstreamResponse, {
161
+ maxBytes: SEARCH_RESPONSE_MAX_BYTES,
107
162
  signal: linkedSignal.signal,
108
163
  });
109
- const payload = await upstreamResponse.arrayBuffer();
110
- if (payload.byteLength > SEARCH_RESPONSE_MAX_BYTES) {
111
- return formatErrorResponse(502, "upstream_error", `search response too large (${payload.byteLength} bytes)`);
164
+ if (observed.oversized) {
165
+ upstream.recordOutcome?.(upstreamResponse.status);
166
+ return formatErrorResponse(
167
+ 502,
168
+ "upstream_error",
169
+ `search response too large (exceeded ${SEARCH_RESPONSE_MAX_BYTES} bytes)`,
170
+ );
112
171
  }
113
172
  upstream.recordOutcome?.(upstreamResponse.status);
114
173
  const relayHeaders: Record<string, string> = {};
115
174
  const contentType = upstreamResponse.headers.get("content-type");
116
175
  if (contentType) relayHeaders["content-type"] = contentType;
117
- return new Response(payload, { status: upstreamResponse.status, headers: relayHeaders });
176
+ return new Response(observed.bytes, { status: upstreamResponse.status, headers: relayHeaders });
118
177
  } catch (err) {
119
178
  if (req.signal.aborted) {
120
179
  return formatErrorResponse(499, "client_closed_request", "search request canceled by client");
121
180
  }
122
- if (err instanceof Error && err.name === "TimeoutError") {
181
+ if (linkedSignal.signal.aborted || (err instanceof Error && err.name === "TimeoutError")) {
123
182
  upstream.recordOutcome?.("timeout");
124
183
  return formatErrorResponse(504, "upstream_error", "search upstream timed out");
125
184
  }
@@ -132,5 +191,11 @@ export async function handleSearch(
132
191
  } finally {
133
192
  sidecarExit();
134
193
  linkedSignal.cleanup();
194
+ // A response that aborted before the reader attached still owns its upstream socket.
195
+ // Consumed/cancelled bodies are already closed; locked bodies remain owned by the reader.
196
+ const pendingBody = upstreamResponse?.body;
197
+ if (pendingBody && !pendingBody.locked) {
198
+ try { void pendingBody.cancel().catch(() => undefined); } catch { /* already closed */ }
199
+ }
135
200
  }
136
201
  }
@@ -0,0 +1,292 @@
1
+ export const MAX_CLIENT_SSE_FRAME_BYTES = 4 * 1024 * 1024;
2
+
3
+ const LF_LF = Uint8Array.of(10, 10);
4
+ const LF_CR_LF = Uint8Array.of(10, 13, 10);
5
+ const CR_LF_LF = Uint8Array.of(13, 10, 10);
6
+ const CR_LF_CR_LF = Uint8Array.of(13, 10, 13, 10);
7
+
8
+ export class SseFrameTooLargeError extends Error {
9
+ readonly maxBytes: number;
10
+
11
+ constructor(maxBytes: number) {
12
+ super(`upstream SSE frame exceeded ${maxBytes} bytes`);
13
+ this.name = "SseFrameTooLargeError";
14
+ this.maxBytes = maxBytes;
15
+ }
16
+ }
17
+
18
+ export class SseFrameCountLimitError extends Error {
19
+ readonly maxFrames: number;
20
+
21
+ constructor(maxFrames: number) {
22
+ super(`upstream SSE chunk exceeded ${maxFrames} frame limit`);
23
+ this.name = "SseFrameCountLimitError";
24
+ this.maxFrames = maxFrames;
25
+ }
26
+ }
27
+
28
+ export type BoundedSseFrame = {
29
+ block: Uint8Array;
30
+ delimiter: Uint8Array;
31
+ };
32
+
33
+ /**
34
+ * Classify the bytes at `index` as an SSE block delimiter.
35
+ *
36
+ * Returns the delimiter length in bytes, `0` when `index` does not start a
37
+ * delimiter, and `undefined` when more bytes are required to decide.
38
+ */
39
+ function delimiterLengthAt(
40
+ index: number,
41
+ length: number,
42
+ byteAt: (index: number) => number,
43
+ ): number | undefined {
44
+ const first = byteAt(index);
45
+ if (first === 10) {
46
+ if (index + 1 >= length) return undefined;
47
+ const second = byteAt(index + 1);
48
+ if (second === 10) return 2;
49
+ if (second !== 13) return 0;
50
+ if (index + 2 >= length) return undefined;
51
+ return byteAt(index + 2) === 10 ? 3 : 0;
52
+ }
53
+ if (first !== 13) return 0;
54
+ if (index + 1 >= length) return undefined;
55
+ if (byteAt(index + 1) !== 10) return 0;
56
+ if (index + 2 >= length) return undefined;
57
+ const third = byteAt(index + 2);
58
+ if (third === 10) return 3;
59
+ if (third !== 13) return 0;
60
+ if (index + 3 >= length) return undefined;
61
+ return byteAt(index + 3) === 10 ? 4 : 0;
62
+ }
63
+
64
+ function delimiterBytesAt(
65
+ index: number,
66
+ delimiterLength: number,
67
+ byteAt: (index: number) => number,
68
+ ): Uint8Array {
69
+ if (delimiterLength === 2) return LF_LF;
70
+ if (delimiterLength === 4) return CR_LF_CR_LF;
71
+ return byteAt(index) === 10 ? LF_CR_LF : CR_LF_LF;
72
+ }
73
+
74
+ function copyRange(
75
+ start: number,
76
+ end: number,
77
+ tailLength: number,
78
+ previousTail: Uint8Array,
79
+ chunk: Uint8Array,
80
+ ): Uint8Array {
81
+ const out = new Uint8Array(end - start);
82
+ for (let index = start; index < end; index += 1) {
83
+ out[index - start] = index < tailLength
84
+ ? previousTail[index]!
85
+ : chunk[index - tailLength]!;
86
+ }
87
+ return out;
88
+ }
89
+
90
+ /**
91
+ * True when a complete SSE block already commits a Responses terminal event.
92
+ *
93
+ * Framing errors in bytes *after* such a block must not retroactively turn an
94
+ * already-completed/failed/incomplete model turn into a transport failure. This
95
+ * helper is used only on the exceptional path, so decoding/JSON parsing has no
96
+ * cost on ordinary framing.
97
+ */
98
+ function isResponsesTerminalFrame(block: Uint8Array): boolean {
99
+ const data: string[] = [];
100
+ for (const line of new TextDecoder().decode(block).split(/\r?\n/)) {
101
+ if (!line.startsWith("data:")) continue;
102
+ const value = line.slice(5);
103
+ data.push(value.startsWith(" ") ? value.slice(1) : value);
104
+ }
105
+ if (data.length === 0) return false;
106
+ const payload = data.join("\n");
107
+ if (payload === "[DONE]") return false;
108
+ try {
109
+ const parsed = JSON.parse(payload) as { type?: unknown };
110
+ return parsed.type === "response.completed"
111
+ || parsed.type === "response.failed"
112
+ || parsed.type === "response.incomplete";
113
+ } catch {
114
+ return false;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Byte-bounded SSE block framer for client-facing protocol paths.
120
+ *
121
+ * The delimiter scanner works on raw bytes, so fragmented UTF-8 cannot change
122
+ * accounting and a hostile upstream cannot grow an unterminated JS string
123
+ * without limit. Candidate bytes live in one geometrically grown buffer rather
124
+ * than one allocation per upstream chunk, bounding both bytes and object count.
125
+ * Complete blocks are returned without their delimiter; the exact delimiter
126
+ * bytes are returned separately so callers can relay bytes unchanged.
127
+ */
128
+ export class BoundedSseFrameBuffer {
129
+ private readonly maxFrameBytes: number;
130
+ private readonly maxFramesPerFeed: number;
131
+ private delimiterTail: Uint8Array = new Uint8Array(0);
132
+ private candidate: Uint8Array = new Uint8Array(0);
133
+ private candidateBytes = 0;
134
+ private disposed = false;
135
+
136
+ constructor(maxFrameBytes = MAX_CLIENT_SSE_FRAME_BYTES) {
137
+ if (!Number.isSafeInteger(maxFrameBytes) || maxFrameBytes <= 0) {
138
+ throw new RangeError("maxFrameBytes must be a positive safe integer");
139
+ }
140
+ this.maxFrameBytes = maxFrameBytes;
141
+ // Delimiter-only input otherwise creates an object-amplification path that
142
+ // is independent of candidate bytes. Keep frame count proportional to the
143
+ // configured byte budget while leaving ample room for real Responses events.
144
+ this.maxFramesPerFeed = Math.max(1, Math.ceil(maxFrameBytes / 1024));
145
+ }
146
+
147
+ private clear(): void {
148
+ this.delimiterTail = new Uint8Array(0);
149
+ this.candidate = new Uint8Array(0);
150
+ this.candidateBytes = 0;
151
+ }
152
+
153
+ private ensureCapacity(requiredBytes: number): void {
154
+ if (this.candidate.byteLength >= requiredBytes) return;
155
+ if (requiredBytes > this.maxFrameBytes) {
156
+ throw new SseFrameTooLargeError(this.maxFrameBytes);
157
+ }
158
+ let capacity = this.candidate.byteLength === 0
159
+ ? Math.min(this.maxFrameBytes, Math.max(requiredBytes, 4096))
160
+ : this.candidate.byteLength;
161
+ while (capacity < requiredBytes) {
162
+ capacity = Math.min(this.maxFrameBytes, Math.max(requiredBytes, capacity * 2));
163
+ }
164
+ const grown = new Uint8Array(capacity);
165
+ if (this.candidateBytes > 0) {
166
+ grown.set(this.candidate.subarray(0, this.candidateBytes));
167
+ }
168
+ this.candidate = grown;
169
+ }
170
+
171
+ private retain(slice: Uint8Array): void {
172
+ if (slice.byteLength === 0) return;
173
+ const nextBytes = this.candidateBytes + slice.byteLength;
174
+ if (nextBytes > this.maxFrameBytes) {
175
+ this.clear();
176
+ this.disposed = true;
177
+ throw new SseFrameTooLargeError(this.maxFrameBytes);
178
+ }
179
+ this.ensureCapacity(nextBytes);
180
+ this.candidate.set(slice, this.candidateBytes);
181
+ this.candidateBytes = nextBytes;
182
+ }
183
+
184
+ private takeCandidate(): Uint8Array {
185
+ if (this.candidateBytes === 0) return new Uint8Array(0);
186
+ const block = this.candidate.slice(0, this.candidateBytes);
187
+ // Release the working allocation after each complete frame. This avoids
188
+ // retaining a rare multi-MiB frame allocation for the rest of a long-lived
189
+ // stream; normal small-frame allocation remains bounded by feed's frame cap.
190
+ this.candidate = new Uint8Array(0);
191
+ this.candidateBytes = 0;
192
+ return block;
193
+ }
194
+
195
+ feed(chunk: Uint8Array): BoundedSseFrame[] {
196
+ if (this.disposed) return [];
197
+ if (chunk.byteLength === 0) return [];
198
+
199
+ const frames: BoundedSseFrame[] = [];
200
+ const previousTail = this.delimiterTail;
201
+ this.delimiterTail = new Uint8Array(0);
202
+ const tailLength = previousTail.byteLength;
203
+ const totalLength = tailLength + chunk.byteLength;
204
+ const byteAt = (index: number): number => index < tailLength
205
+ ? previousTail[index]!
206
+ : chunk[index - tailLength]!;
207
+ const retainRange = (start: number, end: number): void => {
208
+ if (end <= start) return;
209
+ if (start < tailLength) {
210
+ this.retain(previousTail.subarray(start, Math.min(end, tailLength)));
211
+ }
212
+ if (end > tailLength) {
213
+ this.retain(chunk.subarray(Math.max(0, start - tailLength), end - tailLength));
214
+ }
215
+ };
216
+
217
+ try {
218
+ let index = 0;
219
+ let retainedThrough = 0;
220
+ while (index < totalLength) {
221
+ const delimiterLength = delimiterLengthAt(index, totalLength, byteAt);
222
+ if (delimiterLength === undefined) break;
223
+ if (delimiterLength > 0) {
224
+ if (frames.length >= this.maxFramesPerFeed) {
225
+ this.clear();
226
+ this.disposed = true;
227
+ throw new SseFrameCountLimitError(this.maxFramesPerFeed);
228
+ }
229
+ retainRange(retainedThrough, index);
230
+ const block = this.takeCandidate();
231
+ const delimiter = delimiterBytesAt(index, delimiterLength, byteAt);
232
+ frames.push({ block, delimiter });
233
+ index += delimiterLength;
234
+ retainedThrough = index;
235
+ continue;
236
+ }
237
+ index += 1;
238
+ }
239
+
240
+ retainRange(retainedThrough, index);
241
+ if (index < totalLength) {
242
+ this.delimiterTail = copyRange(index, totalLength, tailLength, previousTail, chunk);
243
+ }
244
+ return frames;
245
+ } catch (err) {
246
+ const framingError = err instanceof SseFrameTooLargeError
247
+ || err instanceof SseFrameCountLimitError;
248
+ if (framingError && frames.some(frame => isResponsesTerminalFrame(frame.block))) {
249
+ // A terminal frame is the Responses protocol boundary. Ignore malformed
250
+ // or oversized bytes that occur later in the same upstream chunk rather
251
+ // than retroactively replacing the committed terminal with a 502.
252
+ this.clear();
253
+ this.disposed = true;
254
+ return frames;
255
+ }
256
+ throw err;
257
+ }
258
+ }
259
+
260
+ /** Return the final unterminated block bytes and release all retained state. */
261
+ finish(): Uint8Array {
262
+ if (this.disposed) return new Uint8Array(0);
263
+ try {
264
+ this.retain(this.delimiterTail);
265
+ this.delimiterTail = new Uint8Array(0);
266
+ return this.takeCandidate();
267
+ } finally {
268
+ this.clear();
269
+ this.disposed = true;
270
+ }
271
+ }
272
+
273
+ dispose(): void {
274
+ if (this.disposed) return;
275
+ this.clear();
276
+ this.disposed = true;
277
+ }
278
+ }
279
+
280
+ export function joinSseFrameBytes(parts: readonly Uint8Array[]): Uint8Array {
281
+ let byteLength = 0;
282
+ for (const part of parts) byteLength += part.byteLength;
283
+ if (byteLength === 0) return new Uint8Array(0);
284
+ if (parts.length === 1 && parts[0]!.byteLength === byteLength) return parts[0]!;
285
+ const joined = new Uint8Array(byteLength);
286
+ let offset = 0;
287
+ for (const part of parts) {
288
+ joined.set(part, offset);
289
+ offset += part.byteLength;
290
+ }
291
+ return joined;
292
+ }