@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,185 @@
1
+ /**
2
+ * Pre-dispatch input admission (#1412).
3
+ *
4
+ * Refuses a turn whose estimated input cannot plausibly fit the model context window,
5
+ * BEFORE auth resolution, circuit admission, or any upstream I/O. #1412 reported ~127k of
6
+ * real context compounding to 1.3M-1.6M tokens and crashing the proxy; the provider would
7
+ * reject such a turn anyway, so paying for the round trip buys nothing.
8
+ *
9
+ * Deliberately narrow. This is not a context manager and not a compaction trigger: it
10
+ * catches the pathological case and stays out of the way otherwise. Every uncertainty
11
+ * resolves toward admitting.
12
+ */
13
+ import { nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, type NativeContextLimitsInput } from "../../codex/catalog/metadata";
14
+ import { estimateTokens } from "../../lib/token-estimate";
15
+ import { isCanonicalOpenAiForwardProvider, OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
16
+ import { modelRecordValue } from "../../reasoning-effort";
17
+ import type { OcxContentPart, OcxParsedRequest, OcxProviderConfig } from "../../types";
18
+
19
+ /**
20
+ * Multiplier applied to the ceiling before refusing.
21
+ *
22
+ * 2.5, not something tighter, because `estimateTokens` can overshoot by 1.6x on its own.
23
+ * `cjkRatio` samples every `stride`-th character, so a payload of fixed-width records whose
24
+ * length aligns with the stride samples as 100% CJK while being ~1.6% CJK, firing the
25
+ * 2.5-chars/token clamp instead of the 4.0 default. Measured on Bun 1.3.14: 126,046 chars,
26
+ * true CJK ratio 0.0161, sampled ratio 1.0, estimate inflated 1.6x. Since 4.0 / 2.5 = 1.6
27
+ * is that branch maximum divergence, a threshold at or under 1.6 would convert the
28
+ * estimator error bar into false 413s.
29
+ *
30
+ * 2.5 sits above it with room for the ~10% model-family ratio spread, and still refuses the
31
+ * #1412 shape (10x) four times over.
32
+ */
33
+ export const ADMISSION_TOLERANCE = 2.5;
34
+
35
+ /**
36
+ * Token cost charged for a remote image URL. The bytes are not in this request — the
37
+ * provider fetches them — so the URL own length is not the cost. A small flat charge
38
+ * acknowledges the tiles the image will occupy without pretending to know its dimensions.
39
+ */
40
+ const REMOTE_IMAGE_TOKENS = 850;
41
+
42
+ /** Decoded image bytes per token. Coarse tile-count proxy, not a provider formula. */
43
+ const IMAGE_BYTES_PER_TOKEN = 750;
44
+
45
+ export interface InputAdmissionResult {
46
+ admitted: boolean;
47
+ estimatedTokens: number;
48
+ /** Resolved ceiling, or null when nothing could be resolved (=> always admitted). */
49
+ ceiling: number | null;
50
+ }
51
+
52
+ function positive(value: unknown): number | null {
53
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
54
+ }
55
+
56
+ /**
57
+ * Charge a `data:` URL by its DECODED size rather than its character length: base64 inflates
58
+ * by 4/3, so charging the string would overcount by a third. A remote URL is charged flat.
59
+ */
60
+ function imageTokens(imageUrl: string): number {
61
+ if (!imageUrl.startsWith("data:")) return REMOTE_IMAGE_TOKENS;
62
+ const comma = imageUrl.indexOf(",");
63
+ if (comma < 0) return REMOTE_IMAGE_TOKENS;
64
+ const payload = imageUrl.length - comma - 1;
65
+ if (payload <= 0) return 0;
66
+ const decoded = Math.floor((payload * 3) / 4);
67
+ return Math.max(1, Math.ceil(decoded / IMAGE_BYTES_PER_TOKEN));
68
+ }
69
+
70
+ function contentPartTokens(part: OcxContentPart, modelId: string): number {
71
+ return part.type === "image" ? imageTokens(part.imageUrl) : estimateTokens(part.text, modelId);
72
+ }
73
+
74
+ function contentTokens(content: string | readonly OcxContentPart[], modelId: string): number {
75
+ if (typeof content === "string") return estimateTokens(content, modelId);
76
+ let total = 0;
77
+ for (const part of content) total += contentPartTokens(part, modelId);
78
+ return total;
79
+ }
80
+
81
+ /**
82
+ * Estimate the input tokens of a parsed request.
83
+ *
84
+ * Walks the whole `OcxMessage` union rather than user text alone. Assistant turns carry
85
+ * their content as `OcxAssistantContentPart[]` — text, thinking blocks, and tool calls whose
86
+ * JSON arguments are frequently the largest single item in an agent conversation. A walk
87
+ * that counted only `{type:"text"}` would undercount exactly the turns that trigger this
88
+ * gate.
89
+ */
90
+ export function estimateInputTokens(parsed: OcxParsedRequest, modelId: string): number {
91
+ const { context } = parsed;
92
+ let total = 0;
93
+
94
+ for (const prompt of context.systemPrompt ?? []) total += estimateTokens(prompt, modelId);
95
+
96
+ for (const message of context.messages) {
97
+ if (message.role === "assistant") {
98
+ for (const part of message.content) {
99
+ if (part.type === "text") total += estimateTokens(part.text, modelId);
100
+ else if (part.type === "thinking") total += estimateTokens(part.thinking, modelId);
101
+ else total += estimateTokens(part.name, modelId) + estimateTokens(JSON.stringify(part.arguments), modelId);
102
+ }
103
+ // Opaque provider blob replayed verbatim upstream, so it costs real input tokens.
104
+ if (message.kiroRedactedReasoning) total += estimateTokens(message.kiroRedactedReasoning, modelId);
105
+ continue;
106
+ }
107
+ total += contentTokens(message.content, modelId);
108
+ }
109
+
110
+ // Tool schemas ride every turn: name, description, and the JSON parameter schema all
111
+ // reach the upstream, and a large MCP catalog can dominate a short conversation.
112
+ for (const tool of context.tools ?? []) {
113
+ total += estimateTokens(tool.name, modelId)
114
+ + estimateTokens(tool.description, modelId)
115
+ + estimateTokens(JSON.stringify(tool.parameters), modelId);
116
+ }
117
+
118
+ return total;
119
+ }
120
+
121
+ /**
122
+ * Resolve the admission ceiling. Pure: no filesystem, no catalog, no registry scan.
123
+ *
124
+ * `provider` must be the ROUTED config (`route.provider`), which `routedProviderConfig`
125
+ * has already transport-guarded and merged. Re-deriving from `config.providers[name]` would
126
+ * reject a user-defined provider that merely shares a built-in name using limits that
127
+ * belong to a different service.
128
+ */
129
+ export function resolveInputCeiling(
130
+ provider: OcxProviderConfig,
131
+ providerName: string,
132
+ modelId: string,
133
+ // Operator cap for the canonical native provider. Passed in rather than read from a
134
+ // config here so this stays pure: no filesystem, no catalog, no registry scan.
135
+ nativeContextCap?: NativeContextLimitsInput,
136
+ ): number | null {
137
+ // `modelRecordValue`, not a bare lookup: the catalog resolves these same two maps that
138
+ // way, so a `gpt-oss` entry covers `gpt-oss:120b`. Reading raw here made the gate fall
139
+ // back to the provider-wide window and refuse turns the model can plainly hold.
140
+ const configured = positive(modelRecordValue(provider.modelContextWindows, modelId))
141
+ ?? positive(provider.contextWindow);
142
+
143
+ // The canonical `openai` registry entry declares no context fields, so without this the
144
+ // gate would be inert on the default Codex route. All three clauses are load-bearing: a
145
+ // transport-mismatched custom provider named "openai" is preserved verbatim by routing
146
+ // and must not inherit built-in native limits, and a routed `provider/model` id is not a
147
+ // native slug. Static maps only — no catalog read.
148
+ const canonicalNativeBare = providerName === OPENAI_CODEX_PROVIDER_ID
149
+ && isCanonicalOpenAiForwardProvider(provider)
150
+ && !modelId.includes("/");
151
+ const nativeLimits = canonicalNativeBare && configured !== null
152
+ ? {
153
+ ...(typeof nativeContextCap === "number" ? { cap: nativeContextCap } : (nativeContextCap ?? {})),
154
+ modelWindows: { [modelId]: configured },
155
+ }
156
+ : nativeContextCap;
157
+ const native = canonicalNativeBare
158
+ ? positive(nativeOpenAiContextWindow(modelId, nativeLimits))
159
+ : null;
160
+ const nativeMaxInput = canonicalNativeBare ? positive(nativeOpenAiMaxInputTokens(modelId, nativeLimits)) : null;
161
+
162
+ const window = canonicalNativeBare ? native : configured;
163
+ // modelMaxInputTokens is an input-only cap, so it can only tighten the window.
164
+ const configuredMaxInput = positive(modelRecordValue(provider.modelMaxInputTokens, modelId));
165
+ const limits = [window, configuredMaxInput, nativeMaxInput].filter((v): v is number => v !== null);
166
+ return limits.length === 0 ? null : Math.min(...limits);
167
+ }
168
+
169
+ /**
170
+ * Fail-open when no ceiling is known; refuse only past `ceiling * ADMISSION_TOLERANCE`.
171
+ *
172
+ * The caller is responsible for skipping compaction turns — see the call site in core.ts.
173
+ */
174
+ export function checkInputAdmission(
175
+ parsed: OcxParsedRequest,
176
+ provider: OcxProviderConfig,
177
+ providerName: string,
178
+ modelId: string,
179
+ nativeContextCap?: NativeContextLimitsInput,
180
+ ): InputAdmissionResult {
181
+ const ceiling = resolveInputCeiling(provider, providerName, modelId, nativeContextCap);
182
+ if (ceiling === null) return { admitted: true, estimatedTokens: 0, ceiling: null };
183
+ const estimatedTokens = estimateInputTokens(parsed, modelId);
184
+ return { admitted: estimatedTokens <= ceiling * ADMISSION_TOLERANCE, estimatedTokens, ceiling };
185
+ }
@@ -0,0 +1,13 @@
1
+ import { formatErrorResponse } from "../../bridge";
2
+ import { RequestPacingQueueOverloadError } from "../../providers/request-pacing";
3
+
4
+ /** Convert local request-pacing admission failures into a retryable HTTP response. */
5
+ export function requestPacingOverloadResponse(error: unknown): Response | undefined {
6
+ if (!(error instanceof RequestPacingQueueOverloadError)) return undefined;
7
+ return formatErrorResponse(
8
+ 429,
9
+ "rate_limit_error",
10
+ error.message,
11
+ { retryAfter: String(error.retryAfterSeconds) },
12
+ );
13
+ }
@@ -0,0 +1,178 @@
1
+ import { comboFailureDecision } from "../../combos/failover";
2
+ import { readBoundedResponseBody } from "../../lib/bounded-body";
3
+ import { readJsonRequestBody } from "../request-decompress";
4
+ import { finishRequestAttempt, type RequestLogContext } from "../request-log";
5
+ import type { OcxConfig } from "../../types";
6
+ import type { RouteCandidateTrace, RouteDecisionTraceV1 } from "../../routing/trace";
7
+ import { handleResponses as handleResponsesCore } from "./core";
8
+ import { requestPacingOverloadResponse } from "./pacing-overload";
9
+
10
+ type CoreHandler = typeof handleResponsesCore;
11
+ type CoreOptions = Parameters<CoreHandler>[3];
12
+
13
+ export interface PolicyFallbackDeps {
14
+ runCore?: CoreHandler;
15
+ }
16
+
17
+ function candidateKey(candidate: Pick<RouteCandidateTrace, "provider" | "model">): string {
18
+ return `${candidate.provider}\u0000${candidate.model}`;
19
+ }
20
+
21
+ /**
22
+ * Rank the remaining candidates from the ORIGINAL policy trace. The initial
23
+ * decision stays immutable; fallback execution belongs in attempts[], not in a
24
+ * rewritten decision trace.
25
+ */
26
+ export function rankPolicyFallbackCandidates(
27
+ trace: RouteDecisionTraceV1,
28
+ tried: ReadonlySet<string>,
29
+ ): RouteCandidateTrace[] {
30
+ return trace.candidates
31
+ .map((candidate, index) => ({ candidate, index }))
32
+ .filter(({ candidate }) =>
33
+ candidate.eligible
34
+ && candidate.exclusions.length === 0
35
+ && !tried.has(candidateKey(candidate)))
36
+ .sort((left, right) => {
37
+ const scoreDelta = (right.candidate.score?.total ?? Number.NEGATIVE_INFINITY)
38
+ - (left.candidate.score?.total ?? Number.NEGATIVE_INFINITY);
39
+ return scoreDelta || left.index - right.index;
40
+ })
41
+ .map(({ candidate }) => candidate);
42
+ }
43
+
44
+ function requestWithCandidate(
45
+ req: Request,
46
+ rawBody: Record<string, unknown>,
47
+ candidate: Pick<RouteCandidateTrace, "provider" | "model">,
48
+ ): Request {
49
+ const headers = new Headers(req.headers);
50
+ headers.delete("content-encoding");
51
+ headers.delete("content-length");
52
+ headers.set("content-type", "application/json");
53
+ return new Request(req.url, {
54
+ method: req.method,
55
+ headers,
56
+ body: JSON.stringify({ ...rawBody, model: `${candidate.provider}/${candidate.model}` }),
57
+ signal: req.signal,
58
+ });
59
+ }
60
+
61
+ function errorCodeFromText(text: string): string | undefined {
62
+ if (!text) return undefined;
63
+ try {
64
+ const payload = JSON.parse(text) as { error?: { code?: unknown; type?: unknown }; code?: unknown };
65
+ const candidate = payload.error?.code ?? payload.error?.type ?? payload.code;
66
+ return typeof candidate === "string" ? candidate : undefined;
67
+ } catch {
68
+ return undefined;
69
+ }
70
+ }
71
+
72
+ async function shouldHopPolicyCandidate(response: Response, signal?: AbortSignal): Promise<boolean> {
73
+ if (response.status < 400 || signal?.aborted) return false;
74
+ try {
75
+ const inspected = await readBoundedResponseBody(response.clone(), { signal });
76
+ const text = inspected.displaySafe ? inspected.text : "";
77
+ return comboFailureDecision(response.status, text, { code: errorCodeFromText(text) }) === "hop";
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+
83
+ function isPolicyDecision(trace: RouteDecisionTraceV1 | undefined): trace is RouteDecisionTraceV1 {
84
+ return trace?.routeKind === "policy" && !!trace.profile;
85
+ }
86
+
87
+ /** Finalize the failed physical attempt so the retry receives a fresh attempt row. */
88
+ function finishFailedPolicyAttempt(logCtx: RequestLogContext, status: number): void {
89
+ const attempt = logCtx.activeAttempt;
90
+ if (attempt) {
91
+ const startedAt = logCtx.activeAttemptStartedAt ?? Date.now();
92
+ finishRequestAttempt(attempt, status, Math.max(0, Date.now() - startedAt), attempt.usage ?? logCtx.usage);
93
+ }
94
+ delete logCtx.activeAttempt;
95
+ delete logCtx.activeAttemptStartedAt;
96
+ delete logCtx.usage;
97
+ delete logCtx.usageFromBridge;
98
+ delete logCtx.upstreamError;
99
+ delete logCtx.terminalHttpStatus;
100
+ delete logCtx.terminalErrorCode;
101
+ delete logCtx.terminalIncompleteReason;
102
+ }
103
+
104
+ /**
105
+ * Run a Responses request and, only for an explicitly selected policy profile,
106
+ * hop to the next eligible policy candidate after a retryable pre-success
107
+ * failure. The initial policy trace remains the canonical selection evidence;
108
+ * physical retries continue to accumulate in the existing request attempts.
109
+ */
110
+ export async function handleResponsesWithPolicyFallback(
111
+ req: Request,
112
+ config: OcxConfig,
113
+ logCtx: RequestLogContext,
114
+ options: CoreOptions = {},
115
+ deps: PolicyFallbackDeps = {},
116
+ ): Promise<Response> {
117
+ const runCore = deps.runCore ?? handleResponsesCore;
118
+ let requestBodyReadNotified = false;
119
+ const coreOptions: CoreOptions = options.onRequestBodyRead
120
+ ? {
121
+ ...options,
122
+ onRequestBodyRead: () => {
123
+ if (requestBodyReadNotified) return;
124
+ requestBodyReadNotified = true;
125
+ options.onRequestBodyRead?.();
126
+ },
127
+ }
128
+ : options;
129
+ let rawBody: Record<string, unknown> | null = null;
130
+ try {
131
+ const parsed = await readJsonRequestBody(req.clone());
132
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) rawBody = parsed as Record<string, unknown>;
133
+ } catch {
134
+ // Core owns the client-facing parse/decompression error.
135
+ }
136
+
137
+ let response: Response;
138
+ try {
139
+ response = await runCore(req, config, logCtx, coreOptions);
140
+ } catch (error) {
141
+ const overload = requestPacingOverloadResponse(error);
142
+ if (overload) return overload;
143
+ throw error;
144
+ }
145
+ const initialTrace = logCtx.routeDecision;
146
+ const initialRequestedModel = logCtx.requestedModel;
147
+ if (!rawBody || !isPolicyDecision(initialTrace)) return response;
148
+
149
+ const tried = new Set<string>([
150
+ candidateKey({ provider: initialTrace.selected.provider, model: initialTrace.selected.model }),
151
+ ]);
152
+
153
+ while (await shouldHopPolicyCandidate(response, req.signal)) {
154
+ if (req.signal.aborted) return response;
155
+ const next = rankPolicyFallbackCandidates(initialTrace, tried)[0];
156
+ if (!next) return response;
157
+ tried.add(candidateKey(next));
158
+
159
+ finishFailedPolicyAttempt(logCtx, response.status);
160
+ const retryRequest = requestWithCandidate(req, rawBody, next);
161
+ try {
162
+ try {
163
+ response = await runCore(retryRequest, config, logCtx, coreOptions);
164
+ } catch (error) {
165
+ const overload = requestPacingOverloadResponse(error);
166
+ if (overload) return overload;
167
+ throw error;
168
+ }
169
+ } finally {
170
+ logCtx.requestedModel = initialRequestedModel;
171
+ logCtx.routeDecision = initialTrace;
172
+ }
173
+ }
174
+
175
+ return response;
176
+ }
177
+
178
+ export const handleResponses = handleResponsesWithPolicyFallback;
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Stateless SSE block rewrite that backfills the `annotations` field on
3
+ * `output_text` content parts in Responses SSE events.
4
+ *
5
+ * The Responses API spec defines `annotations` as a required field on
6
+ * `OutputTextContent` (it is `Vec<Annotation>`, not `Option<Vec>`). Some
7
+ * upstream relays omit it when there are no annotations, which is technically
8
+ * spec-non-compliant. Strict deserializers — any client that follows the
9
+ * schema without `#[serde(default)]` on that field — fail with
10
+ * `missing field `annotations`` when the field is absent.
11
+ *
12
+ * This rewrite scans every SSE event for output_text content parts — whether
13
+ * they appear in item.content[], part, or response.output[].content[] — and
14
+ * adds annotations: [] if missing.
15
+ *
16
+ * Stateless: no retained buffers, no lifecycle tracking, no fail-closed.
17
+ * Existing values are always authoritative; only absent fields are added.
18
+ * The field is always valid on the wire, so adding it when absent is safe
19
+ * for all clients including Codex CLI/App.
20
+ */
21
+
22
+ import {
23
+ replaceSseDataPayload,
24
+ sseDataPayload,
25
+ type SseBlockRewrite,
26
+ } from "../sse-payload-rewrite";
27
+ import { isCompactionItemType } from "../../responses/compaction";
28
+
29
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
30
+ return !!value && typeof value === "object" && !Array.isArray(value);
31
+ }
32
+
33
+ /** Wire prefixes for Responses output item ids, matching OpenAI's id shapes. */
34
+ const ITEM_ID_PREFIXES: Readonly<Record<string, string>> = {
35
+ message: "msg_",
36
+ reasoning: "rs_",
37
+ function_call: "fc_",
38
+ custom_tool_call: "ctc_",
39
+ // A routed tool_search lowering is restored to `tool_search_call` without an id, so this
40
+ // backfill is what names it. The generic `item_` fallback is not merely cosmetic here:
41
+ // `stripInvalidItemIds` in the Responses adapter deletes any id whose prefix does not match
42
+ // the type, so an `item_`-named tool_search_call silently loses its id on the NEXT turn and
43
+ // the client sees an item it cannot correlate. The prefixes here must stay a superset of the
44
+ // ones that serializer enforces.
45
+ tool_search_call: "tsc_",
46
+ web_search_call: "ws_",
47
+ file_search_call: "fs_",
48
+ code_interpreter_call: "ci_",
49
+ computer_call: "cc_",
50
+ // The Responses wire type is `image_generation_call`; `image_gen_call` is kept only so a
51
+ // relay that emits the short spelling is not silently demoted to the generic `item_`.
52
+ image_generation_call: "ig_",
53
+ image_gen_call: "ig_",
54
+ };
55
+
56
+ /**
57
+ * Backfill a required id on an output item when absent. Strict Responses
58
+ * decoders (e.g. grok-build serde types) fail with "missing field id" when a
59
+ * message or reasoning item has no id, which some upstream relays omit. The
60
+ * generated id is deterministic per (type, output index) so it stays stable
61
+ * across streaming events that reference the same item.
62
+ */
63
+ function backfillItemId(item: Record<string, unknown>, slot: ItemIdSlot): Record<string, unknown> {
64
+ if (typeof item.id === "string" && item.id.length > 0) return item;
65
+ const type = typeof item.type === "string" ? item.type : "";
66
+ const prefix = Object.prototype.hasOwnProperty.call(ITEM_ID_PREFIXES, type) ? ITEM_ID_PREFIXES[type] : "item_";
67
+ return { ...item, id: prefix + "ocx_" + (slot.kind === "index" ? String(slot.index) : "fallback_" + slot.ordinal) };
68
+ }
69
+
70
+ /**
71
+ * Which namespace a synthesized id comes from.
72
+ *
73
+ * Keeping the fallback counter in the SAME numeric namespace as real output indexes only
74
+ * pushed the collision out of reach rather than removing it: a response whose real index
75
+ * happened to be 1_000_001 would produce the same id as the first malformed-index fallback,
76
+ * and a duplicate id is exactly what this backfill exists to prevent. The namespaces are now
77
+ * lexically disjoint, so no index value can ever collide with a fallback.
78
+ */
79
+ type ItemIdSlot = { kind: "index"; index: number } | { kind: "fallback"; ordinal: number };
80
+
81
+ /**
82
+ * Monotonic ordinal for an event whose `output_index` is absent or malformed.
83
+ *
84
+ * Process-global rather than per-response because this module is stateless by design and the
85
+ * value only has to be unique, not meaningful. It carries its own `fallback_` namespace, so
86
+ * uniqueness no longer depends on a real index never reaching some arbitrary ceiling.
87
+ */
88
+ let syntheticItemOrdinal = 0;
89
+ function nextSyntheticItemSlot(): ItemIdSlot {
90
+ syntheticItemOrdinal += 1;
91
+ return { kind: "fallback", ordinal: syntheticItemOrdinal };
92
+ }
93
+
94
+ /**
95
+ * Backfill annotations: [] on an output_text content part if missing.
96
+ * Returns the same object reference if no change is needed.
97
+ */
98
+ function backfillOutputTextPart(part: Record<string, unknown>): Record<string, unknown> {
99
+ if (part.type !== "output_text") return part;
100
+ // Only add annotations when the key is entirely absent — preserve any
101
+ // existing value (even null or a malformed type) so we never overwrite
102
+ // what the upstream actually sent.
103
+ if ("annotations" in part) return part;
104
+ return { ...part, annotations: [] };
105
+ }
106
+
107
+ /**
108
+ * Walk a content array and backfill output_text parts.
109
+ * Returns the same array reference if nothing changed.
110
+ */
111
+ function backfillContentArray(content: unknown): unknown {
112
+ if (!Array.isArray(content)) return content;
113
+ let changed = false;
114
+ const repaired = content.map((part) => {
115
+ if (!isPlainObject(part)) return part;
116
+ const next = backfillOutputTextPart(part);
117
+ if (next !== part) changed = true;
118
+ return next;
119
+ });
120
+ return changed ? repaired : content;
121
+ }
122
+
123
+ /**
124
+ * Walk an output item and backfill output_text parts in its content.
125
+ * Also backfills a missing required id on the item itself.
126
+ * Returns the same object reference if nothing changed.
127
+ */
128
+ function backfillOutputItem(item: unknown, slot: ItemIdSlot): unknown {
129
+ if (!isPlainObject(item)) return item;
130
+ // The compact wire family is the `/v1/responses/compact` format, not a Responses output item.
131
+ // Those items have no `id` in that contract, so synthesizing one changes a response body the
132
+ // client compares exactly — and the client replays the item on every later turn, where the
133
+ // minting backend rejects it as modified. The backfill exists to satisfy strict Responses
134
+ // decoders; a shape those decoders never see is outside its remit.
135
+ if (isCompactionItemType(item.type)) return item;
136
+ const content = item.content;
137
+ const repaired = backfillContentArray(content);
138
+ const withId = backfillItemId(item, slot);
139
+ if (repaired === content && withId === item) return item;
140
+ return { ...withId, ...(repaired === content ? {} : { content: repaired }) };
141
+ }
142
+
143
+ /**
144
+ * Walk a response object's output[] and backfill output_text parts.
145
+ * Returns the same object reference if nothing changed.
146
+ */
147
+ function backfillResponseOutput(response: unknown): unknown {
148
+ if (!isPlainObject(response)) return response;
149
+ const output = response.output;
150
+ if (!Array.isArray(output)) return response;
151
+ let changed = false;
152
+ const repaired = output.map((item, idx) => {
153
+ if (!isPlainObject(item)) return item;
154
+ const next = backfillOutputItem(item, { kind: "index", index: idx });
155
+ if (next !== item) changed = true;
156
+ return next;
157
+ });
158
+ return changed ? { ...response, output: repaired } : response;
159
+ }
160
+
161
+ /**
162
+ * Statelessly rewrite one SSE event: backfill annotations
163
+ * on any output_text content part found in the event payload.
164
+ */
165
+ function rewriteEvent(event: Record<string, unknown>): Record<string, unknown> {
166
+ const type = typeof event.type === "string" ? event.type : "";
167
+ let next = event;
168
+ let changed = false;
169
+
170
+ // output_item.added / output_item.done: item.content[] -> output_text parts
171
+ if ((type === "response.output_item.added" || type === "response.output_item.done")
172
+ && isPlainObject(event.item)) {
173
+ const rawIndex = event.output_index;
174
+ // A malformed or absent `output_index` must not collapse to 0: two such events would then
175
+ // both synthesize `msg_ocx_0`, and duplicate ids are the very thing this backfill exists to
176
+ // prevent. Fall back to a per-process counter so the synthesized id stays unique. Position
177
+ // is not recoverable in that case, but a unique id is what strict decoders require, and a
178
+ // well-formed stream still gets the stable index-derived id.
179
+ const item = typeof rawIndex === "number" && Number.isInteger(rawIndex) && rawIndex >= 0
180
+ ? backfillOutputItem(event.item, { kind: "index", index: rawIndex })
181
+ : backfillOutputItem(event.item, nextSyntheticItemSlot());
182
+ if (item !== event.item) {
183
+ next = { ...next, item };
184
+ changed = true;
185
+ }
186
+ }
187
+
188
+ // content_part.added / content_part.done: part -> output_text
189
+ if ((type === "response.content_part.added" || type === "response.content_part.done")
190
+ && isPlainObject(event.part)) {
191
+ const part = backfillOutputTextPart(event.part);
192
+ if (part !== event.part) {
193
+ next = { ...next, part };
194
+ changed = true;
195
+ }
196
+ }
197
+
198
+ // response.created / in_progress / completed / incomplete / failed:
199
+ // response.output[].content[] -> output_text parts
200
+ if (isPlainObject(event.response)) {
201
+ const response = backfillResponseOutput(event.response);
202
+ if (response !== event.response) {
203
+ next = { ...next, response };
204
+ changed = true;
205
+ }
206
+ }
207
+
208
+ return changed ? next : event;
209
+ }
210
+
211
+ /**
212
+ * Create a stateless SSE block rewrite that backfills annotations and
213
+ * on output_text content parts. Unconditional: the field is a required
214
+ * canonical Responses field, so adding it when absent is safe for all
215
+ * clients.
216
+ */
217
+ export function createResponsesFieldBackfillBlockRewrite(): SseBlockRewrite {
218
+ const rewrite: SseBlockRewrite = (block: string): readonly string[] => {
219
+ const payload = sseDataPayload(block);
220
+ if (payload === null) return [block];
221
+ let event: unknown;
222
+ try {
223
+ event = JSON.parse(payload);
224
+ } catch {
225
+ return [block];
226
+ }
227
+ if (!isPlainObject(event)) return [block];
228
+ const rewritten = rewriteEvent(event);
229
+ if (rewritten === event) return [block];
230
+ return [replaceSseDataPayload(block, JSON.stringify(rewritten))];
231
+ };
232
+ return rewrite;
233
+ }
234
+
235
+ /**
236
+ * Backfill annotations on a non-streaming Responses JSON
237
+ * object. Mirrors the SSE block rewrite for the bounded-JSON passthrough
238
+ * path. Returns the original string if no change is needed.
239
+ */
240
+ export function backfillResponsesFieldsJson(payload: string): string {
241
+ let response: unknown;
242
+ try {
243
+ response = JSON.parse(payload);
244
+ } catch {
245
+ return payload;
246
+ }
247
+ if (!isPlainObject(response)) return payload;
248
+ const repaired = backfillResponseOutput(response);
249
+ if (repaired === response) return payload;
250
+ return JSON.stringify(repaired);
251
+ }