@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,73 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
2
+ import { isLocalAttestationSecret } from "./local-management-attestation";
3
+
4
+ export const SYSTEM_RESTART_METHOD = "POST";
5
+ export const SYSTEM_RESTART_PATH = "/api/system/restart";
6
+ export const SYSTEM_RESTART_CAPABILITY_VERSION = "v1";
7
+ export const SYSTEM_RESTART_EXPECTED_PID_HEADER = "x-opencodex-restart-expected-pid";
8
+ export const SYSTEM_RESTART_NONCE_HEADER = "x-opencodex-restart-nonce";
9
+ export const SYSTEM_RESTART_CAPABILITY_HEADER = "x-opencodex-restart-capability";
10
+
11
+ /** Fixed drain and replacement budgets shared by the server, CLI, and tray. */
12
+ export const MEMORY_DRAIN_RESTART_MS = 60_000;
13
+ export const REPLACEMENT_READY_TIMEOUT_MS = 70_000;
14
+
15
+ const BASE64URL_256 = /^[A-Za-z0-9_-]{43}$/;
16
+
17
+ export type ExpectedSystemRestartPid =
18
+ | { kind: "absent" }
19
+ | { kind: "invalid" }
20
+ | { kind: "present"; pid: number };
21
+
22
+ export function parseExpectedSystemRestartPid(value: string | null): ExpectedSystemRestartPid {
23
+ if (value === null) return { kind: "absent" };
24
+ if (!/^[1-9]\d*$/.test(value)) return { kind: "invalid" };
25
+ const pid = Number(value);
26
+ return Number.isSafeInteger(pid) ? { kind: "present", pid } : { kind: "invalid" };
27
+ }
28
+
29
+ function restartCapabilityPayload(
30
+ nonce: string,
31
+ method: string,
32
+ path: string,
33
+ pid: number,
34
+ port: number,
35
+ ): string | null {
36
+ if (!BASE64URL_256.test(nonce)) return null;
37
+ if (method !== SYSTEM_RESTART_METHOD || path !== SYSTEM_RESTART_PATH) return null;
38
+ if (!Number.isSafeInteger(pid) || pid <= 0) return null;
39
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) return null;
40
+ return `opencodex-system-restart-v1\n${nonce}\n${method}\n${path}\n${pid}\n${port}`;
41
+ }
42
+
43
+ /** Process-scoped, operation-only authorization. It is not a reusable management credential. */
44
+ export function createSystemRestartCapability(
45
+ secret: string,
46
+ nonce: string,
47
+ method: string,
48
+ path: string,
49
+ pid: number,
50
+ port: number,
51
+ ): string | null {
52
+ if (!isLocalAttestationSecret(secret)) return null;
53
+ const payload = restartCapabilityPayload(nonce, method, path, pid, port);
54
+ if (!payload) return null;
55
+ return createHmac("sha256", secret).update(payload).digest("base64url");
56
+ }
57
+
58
+ export function verifySystemRestartCapability(
59
+ secret: string,
60
+ nonce: string | null,
61
+ method: string,
62
+ path: string,
63
+ pid: number,
64
+ port: number,
65
+ capability: string | null,
66
+ ): boolean {
67
+ if (!nonce || !capability || !BASE64URL_256.test(capability)) return false;
68
+ const expected = createSystemRestartCapability(secret, nonce, method, path, pid, port);
69
+ if (!expected) return false;
70
+ const expectedBytes = Buffer.from(expected);
71
+ const actualBytes = Buffer.from(capability);
72
+ return expectedBytes.length === actualBytes.length && timingSafeEqual(expectedBytes, actualBytes);
73
+ }
@@ -55,15 +55,32 @@ function cjkRatio(text: string): number {
55
55
  return sampled === 0 ? 0 : cjk / sampled;
56
56
  }
57
57
 
58
+ /**
59
+ * Cap an estimated token count at a model's context window (codex-router PR #140).
60
+ *
61
+ * A request the provider answered cannot have exceeded the window, so the estimate is never
62
+ * allowed to claim it did: the estimate only ever substitutes a reported-zero (or missing)
63
+ * input count, and a value above the window would be provably false. Positive or missing
64
+ * reported counts are never rewritten here — this bounds the heuristic estimate itself.
65
+ * Non-positive or non-integer windows (unknown model) leave the estimate untouched.
66
+ */
67
+ export function capEstimateAtContextWindow(estimate: number, contextWindow: number | undefined): number {
68
+ return typeof contextWindow === "number" && Number.isInteger(contextWindow) && contextWindow > 0
69
+ ? Math.min(estimate, contextWindow)
70
+ : estimate;
71
+ }
72
+
58
73
  /**
59
74
  * Estimate the token count of a text blob. Pure and deterministic.
60
75
  * Returns 0 for empty/whitespace-free-empty input; otherwise ceil(length / ratio), min 1.
76
+ * When `contextWindow` is a positive integer the estimate is capped at it: a request the
77
+ * provider answered cannot have exceeded the window, so the estimate must not claim it did.
61
78
  */
62
- export function estimateTokens(text: string, modelId?: string): number {
79
+ export function estimateTokens(text: string, modelId?: string, contextWindow?: number): number {
63
80
  if (!text) return 0;
64
81
  const len = text.length;
65
82
  if (len === 0) return 0;
66
83
  let ratio = charsPerToken(modelId);
67
84
  if (cjkRatio(text) > CJK_RATIO_THRESHOLD) ratio = Math.min(ratio, CJK_CHARS_PER_TOKEN);
68
- return Math.max(1, Math.ceil(len / ratio));
85
+ return capEstimateAtContextWindow(Math.max(1, Math.ceil(len / ratio)), contextWindow);
69
86
  }
@@ -0,0 +1,202 @@
1
+ // Schema-aware repair for tool arguments whose serialized representation disagrees
2
+ // with the declared schema in a way that has exactly one faithful reading.
3
+ //
4
+ // Case 1 — integer fields arriving as integral floats (issue #1611).
5
+ //
6
+ // Grok serializes integer tool-call arguments through a float representation, so
7
+ // `yield_time_ms: 120000` leaves the provider as `120000.0`. Codex declares those
8
+ // fields as Rust integer types, so it rejects the call BEFORE running the tool:
9
+ //
10
+ // failed to parse function arguments: invalid type: floating point `120000.0`, expected u64
11
+ //
12
+ // That is a hard failure, not a degradation — the model gets no result and retries
13
+ // the same float. Nothing on the routed path reconciled argument values against the
14
+ // declared schema, so the `.0` passed straight through.
15
+ //
16
+ // The boundary this file draws is INTENT, not convenience:
17
+ // - an integral float in an integer-typed field is a representation artifact, and
18
+ // `120000.0` has exactly one integer reading, so it is repaired;
19
+ // - `1.5` in an integer field is a genuine disagreement with the schema and is left
20
+ // alone so it still fails, rather than being truncated into a plausible lie.
21
+ //
22
+ // Case 2 — string fields arriving as bare integers (issue #1938).
23
+ //
24
+ // Cursor-served models emit `{"cell_id": 4}` where the schema declares
25
+ // `{"type": "string"}`. Codex rejects the call before the tool runs (invalid type:
26
+ // integer `4`, expected a string), and the model never self-corrects, so every such
27
+ // call is a hard failure loop. A safely-integral JSON number in a string-declared
28
+ // field has exactly one faithful string reading (`4` -> `"4"`), so it is repaired
29
+ // under the same intent boundary:
30
+ // - only when the field declares `string` and no numeric type (a
31
+ // `["integer","string"]` union accepts the number as-is and is left alone);
32
+ // - a non-integral number (`4.5`) in a string field is a genuine disagreement and
33
+ // is left alone so it still fails;
34
+ // - beyond 2^53-1 the parsed value may differ from the serialized text, so the
35
+ // original bytes stay.
36
+ //
37
+ // Anything without a declared `integer`/`string` type is never touched.
38
+
39
+ /** JSON Schema subset we need; provider tool schemas are untrusted input. */
40
+ type SchemaNode = Record<string, unknown>;
41
+
42
+ function asSchema(value: unknown): SchemaNode | undefined {
43
+ return value && typeof value === "object" && !Array.isArray(value)
44
+ ? value as SchemaNode
45
+ : undefined;
46
+ }
47
+
48
+ /** True when the node declares `integer`, including `["integer","null"]` unions. */
49
+ function declaresInteger(schema: SchemaNode): boolean {
50
+ const type = schema.type;
51
+ if (type === "integer") return true;
52
+ return Array.isArray(type) && type.includes("integer");
53
+ }
54
+
55
+ /** True when the node declares `string`, including `["string","null"]` unions. */
56
+ function declaresString(schema: SchemaNode): boolean {
57
+ const type = schema.type;
58
+ if (type === "string") return true;
59
+ return Array.isArray(type) && type.includes("string");
60
+ }
61
+
62
+ /** True when the node accepts a JSON number (`integer` or `number`), so a numeric
63
+ * value is already schema-valid and must not be rewritten into a string. */
64
+ function declaresNumeric(schema: SchemaNode): boolean {
65
+ const type = schema.type;
66
+ if (type === "integer" || type === "number") return true;
67
+ return Array.isArray(type) && (type.includes("integer") || type.includes("number"));
68
+ }
69
+
70
+ /**
71
+ * Resolve a local `$ref` (`#/$defs/Foo`, `#/definitions/Foo`).
72
+ *
73
+ * Only same-document refs are followed: a remote ref is not fetchable here, and a
74
+ * schema we cannot resolve must leave its values untouched rather than guessed at.
75
+ */
76
+ function resolveRef(schema: SchemaNode, root: SchemaNode, seen: Set<string>): SchemaNode | undefined {
77
+ const ref = schema.$ref;
78
+ if (typeof ref !== "string" || !ref.startsWith("#/")) return schema;
79
+ if (seen.has(ref)) return undefined; // cyclic $ref: stop rather than recurse forever
80
+ seen.add(ref);
81
+ let node: unknown = root;
82
+ for (const rawSegment of ref.slice(2).split("/")) {
83
+ const segment = rawSegment.replace(/~1/g, "/").replace(/~0/g, "~");
84
+ const current = asSchema(node);
85
+ if (!current) return undefined;
86
+ node = current[segment];
87
+ }
88
+ const resolved = asSchema(node);
89
+ return resolved ? resolveRef(resolved, root, seen) : undefined;
90
+ }
91
+
92
+ /** Composition keywords whose branches may carry the integer declaration. */
93
+ const COMPOSITION_KEYS = ["anyOf", "oneOf", "allOf"] as const;
94
+
95
+ function compositionBranches(schema: SchemaNode): SchemaNode[] {
96
+ const branches: SchemaNode[] = [];
97
+ for (const key of COMPOSITION_KEYS) {
98
+ const value = schema[key];
99
+ if (!Array.isArray(value)) continue;
100
+ for (const branch of value) {
101
+ const node = asSchema(branch);
102
+ if (node) branches.push(node);
103
+ }
104
+ }
105
+ return branches;
106
+ }
107
+
108
+ /**
109
+ * A JS number can only represent integers exactly up to 2^53-1. Beyond that a
110
+ * rewrite would emit a silently different value, so the original text stays.
111
+ */
112
+ function safelyIntegral(value: number): boolean {
113
+ return Number.isInteger(value) && Math.abs(value) <= Number.MAX_SAFE_INTEGER;
114
+ }
115
+
116
+ interface CoerceResult {
117
+ value: unknown;
118
+ changed: boolean;
119
+ }
120
+
121
+ function coerceValue(value: unknown, schema: SchemaNode | undefined, root: SchemaNode, depth: number): CoerceResult {
122
+ // A hostile or deeply nested schema must not blow the stack.
123
+ if (depth > 64) return { value, changed: false };
124
+ const resolved = schema ? resolveRef(schema, root, new Set()) : undefined;
125
+
126
+ if (typeof value === "number") {
127
+ if (!resolved) return { value, changed: false };
128
+ const branches = compositionBranches(resolved);
129
+ const integerDeclared = declaresInteger(resolved) || branches.some(declaresInteger);
130
+ if (!integerDeclared && safelyIntegral(value)) {
131
+ // Issue #1938: a bare integer in a string-only field has exactly one faithful
132
+ // string reading. A field that also accepts a numeric type keeps the number.
133
+ const stringDeclared = declaresString(resolved) || branches.some(declaresString);
134
+ const numericDeclared = declaresNumeric(resolved) || branches.some(declaresNumeric);
135
+ if (stringDeclared && !numericDeclared) {
136
+ return { value: String(value), changed: true };
137
+ }
138
+ }
139
+ // Not an integer field, already an integer, non-integral, or unrepresentable:
140
+ // in every one of those cases the received value is the right thing to keep.
141
+ if (!integerDeclared || !safelyIntegral(value)) return { value, changed: false };
142
+ // `120000.0` and `120000` are the same JS number; the difference is only in the
143
+ // serialized text, which is repaired by re-stringifying the parsed value.
144
+ return { value, changed: true };
145
+ }
146
+
147
+ if (Array.isArray(value)) {
148
+ const itemSchema = resolved ? asSchema(resolved.items) : undefined;
149
+ let changed = false;
150
+ const next = value.map(entry => {
151
+ const result = coerceValue(entry, itemSchema, root, depth + 1);
152
+ if (result.changed) changed = true;
153
+ return result.value;
154
+ });
155
+ return changed ? { value: next, changed } : { value, changed: false };
156
+ }
157
+
158
+ const object = asSchema(value);
159
+ if (!object) return { value, changed: false };
160
+
161
+ const properties = resolved ? asSchema(resolved.properties) : undefined;
162
+ const additional = resolved ? asSchema(resolved.additionalProperties) : undefined;
163
+ let changed = false;
164
+ const next: Record<string, unknown> = {};
165
+ for (const [key, entry] of Object.entries(object)) {
166
+ const childSchema = asSchema(properties?.[key]) ?? additional;
167
+ const result = coerceValue(entry, childSchema, root, depth + 1);
168
+ if (result.changed) changed = true;
169
+ next[key] = result.value;
170
+ }
171
+ return changed ? { value: next, changed } : { value, changed: false };
172
+ }
173
+
174
+ /**
175
+ * Repair integral floats in a tool-call arguments STRING against the tool's declared
176
+ * parameter schema.
177
+ *
178
+ * Returns the original string unchanged when there is no schema, the payload does not
179
+ * parse, or nothing needed repair — so an unaffected call keeps its exact bytes and
180
+ * this stays a no-op for every provider that already emits real integers.
181
+ */
182
+ export function coerceIntegerToolArguments(
183
+ args: string,
184
+ parameters: Record<string, unknown> | undefined,
185
+ ): string {
186
+ if (!parameters || !args) return args;
187
+ // Cheap reject: a payload with no digit cannot need either repair (integral-float
188
+ // -> integer, or bare-integer -> string).
189
+ if (!/\d/.test(args)) return args;
190
+ let parsed: unknown;
191
+ try {
192
+ parsed = JSON.parse(args);
193
+ } catch {
194
+ // Malformed or still-streaming arguments are not this function's problem; the
195
+ // existing paths already handle them.
196
+ return args;
197
+ }
198
+ const root = parameters as SchemaNode;
199
+ const result = coerceValue(parsed, root, root, 0);
200
+ if (!result.changed) return args;
201
+ return JSON.stringify(result.value);
202
+ }
@@ -71,6 +71,40 @@ export interface TranslatorBudget {
71
71
 
72
72
  const retainedEventOwnership = new WeakMap<object, { budget: TranslatorBudget; bytes: number }>();
73
73
 
74
+ /**
75
+ * Charge one event appended to an incrementally materialized adapter-event batch.
76
+ * The newest event owns the closing array bracket; moving that byte from the old
77
+ * tail keeps in-order release accounting equal to the still-retained JSON array.
78
+ */
79
+ export function retainTranslatedEvent<T extends object>(
80
+ event: T,
81
+ budget: TranslatorBudget,
82
+ previousTail?: object,
83
+ ): void {
84
+ if (retainedEventOwnership.has(event)) {
85
+ throw new Error("translated event is already retained");
86
+ }
87
+ if (previousTail === event) {
88
+ throw new Error("incremental translated event tail must be a distinct object");
89
+ }
90
+ const previousOwnership = previousTail === undefined
91
+ ? undefined
92
+ : retainedEventOwnership.get(previousTail);
93
+ if (
94
+ previousTail !== undefined
95
+ && (!previousOwnership || previousOwnership.budget !== budget || previousOwnership.bytes < 2)
96
+ ) {
97
+ throw new Error("incremental translated event tail is not retained by this budget");
98
+ }
99
+
100
+ const serializedBytes = Buffer.byteLength(JSON.stringify(event));
101
+ budget.chargeRetained(serializedBytes + (previousTail === undefined ? 2 : 1), {
102
+ kind: "retained_collectors",
103
+ });
104
+ if (previousOwnership) previousOwnership.bytes -= 1;
105
+ retainedEventOwnership.set(event, { budget, bytes: serializedBytes + 2 });
106
+ }
107
+
74
108
  /**
75
109
  * Charge a materialized adapter-event batch and attach its lease to the events themselves.
76
110
  * A copied event array (for example terminal-guard collection) preserves the event objects, so
@@ -315,6 +349,16 @@ export function translatorObservedOverflowCount(): number {
315
349
  return aggregateOverflows;
316
350
  }
317
351
 
352
+ /** Test-only: proves owned default budgets are disposed on every stream-death path. */
353
+ export function translatorLiveBudgetCountForTests(): number {
354
+ return liveBudgets.size;
355
+ }
356
+
357
+ /** Test-only: proves no charge survives against a disposed budget (cancel race). */
358
+ export function translatorAggregateCurrentBytesForTests(): number {
359
+ return aggregateCurrentBytes;
360
+ }
361
+
318
362
  /** Clears process-wide translator diagnostics and disposes leaked test budgets. */
319
363
  export function resetTranslatorAggregateForTests(): void {
320
364
  for (const budget of liveBudgets) budget.dispose();
@@ -0,0 +1,57 @@
1
+ import type { OcxProviderConfig, UpstreamHttpVersion } from "../types";
2
+
3
+ /** True when a provider explicitly selected the HTTP/1.1 compatibility path. */
4
+ export function isPinnedHttp1(version: UpstreamHttpVersion | undefined): boolean {
5
+ return version === "http1.1" || version === "h1";
6
+ }
7
+
8
+ /**
9
+ * Bun's fetch accepts a non-standard `protocol` init to pin the HTTP version
10
+ * (BunFetchRequestInit.protocol). The DOM lib types do not include it, so the
11
+ * value is represented through a RequestInit cast at this shared boundary.
12
+ */
13
+ const UPSTREAM_HTTP_VERSION_PROTOCOL: Record<Exclude<UpstreamHttpVersion, "auto">, string> = {
14
+ "http1.1": "http1.1",
15
+ h1: "h1",
16
+ http2: "http2",
17
+ h2: "h2",
18
+ };
19
+
20
+ /** Raised before I/O when a fixed Bun HTTP-version pin cannot apply to the target URL. */
21
+ export class UpstreamHttpVersionTargetError extends Error {
22
+ readonly code = "upstream_http_version_target";
23
+
24
+ constructor(readonly observedProtocol: string) {
25
+ super(`upstream HTTP version pin requires an HTTPS target (received ${observedProtocol})`);
26
+ this.name = "UpstreamHttpVersionTargetError";
27
+ }
28
+ }
29
+
30
+ /** Attach Bun's `protocol` pin for one explicit version value. */
31
+ export function withUpstreamHttpVersionValue(
32
+ input: Parameters<typeof globalThis.fetch>[0],
33
+ init: RequestInit | undefined,
34
+ version: UpstreamHttpVersion | undefined,
35
+ ): RequestInit | undefined {
36
+ if (!version || version === "auto") return init;
37
+ // Bun's protocol pin requires an https: target. An explicit fixed-version request must fail
38
+ // locally when the pin cannot be honored instead of silently negotiating another transport.
39
+ const target = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
40
+ let targetUrl: URL;
41
+ try {
42
+ targetUrl = new URL(target);
43
+ } catch {
44
+ throw new UpstreamHttpVersionTargetError("unparseable");
45
+ }
46
+ if (targetUrl.protocol !== "https:") throw new UpstreamHttpVersionTargetError(targetUrl.protocol);
47
+ return { ...(init ?? {}), protocol: UPSTREAM_HTTP_VERSION_PROTOCOL[version] } as RequestInit;
48
+ }
49
+
50
+ /** Attach Bun's `protocol` pin when the provider opted into a fixed HTTP version. */
51
+ export function withUpstreamHttpVersion(
52
+ input: Parameters<typeof globalThis.fetch>[0],
53
+ init: RequestInit | undefined,
54
+ provider: Pick<OcxProviderConfig, "upstreamHttpVersion">,
55
+ ): RequestInit | undefined {
56
+ return withUpstreamHttpVersionValue(input, init, provider.upstreamHttpVersion);
57
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Classification of upstream fetch rejections that occur before any request
3
+ * bytes can reach the origin: DNS resolution failure and TCP connect refusal.
4
+ *
5
+ * Issue #914: these failures are machine/network-wide, not account-specific —
6
+ * every Codex pool account shares the provider host, so rotating accounts
7
+ * cannot repair them. The transport layer previously mapped every non-timeout
8
+ * rejection to `connect_error`, and at `upstreamFailoverThreshold` that streak
9
+ * soft-avoided a healthy account and cleared thread affinity.
10
+ *
11
+ * Bun collapses DNS failure and TCP refusal into one label class
12
+ * (`ConnectionRefused` / `FailedToOpenSocket`, errno 0); Node's undici emits
13
+ * the classic `ECONNREFUSED` / `ENOTFOUND` / `EAI_AGAIN` / `ENETUNREACH` /
14
+ * `ENETDOWN` / `EHOSTUNREACH` shapes. Both shapes are matched here, on `code`
15
+ * values only, through a bounded cause chain. Message substrings are never
16
+ * trusted (a message-only match is a negative case), and labels that can also
17
+ * appear after the origin saw the credential — `ECONNRESET`, `EPIPE`, TLS
18
+ * errors, unknown shapes — deliberately stay outside the set.
19
+ *
20
+ * Classifier semantics extracted from PR #966 (Yuxin-Qiao) with attribution;
21
+ * sidecar blast radius intentionally not inherited.
22
+ *
23
+ * MUST stay a leaf module: imports nothing from server.ts or adapters.
24
+ */
25
+
26
+ import { RequestPacingQueueOverloadError } from "../providers/request-pacing";
27
+ import { UpstreamRetryEvidenceError } from "./upstream-retry";
28
+
29
+ export const PRE_CONNECT_REACHABILITY_CODES = new Set([
30
+ // Bun: DNS failure and TCP refusal share this class.
31
+ "ConnectionRefused",
32
+ "FailedToOpenSocket",
33
+ // Node undici / classic Node shapes.
34
+ "ECONNREFUSED",
35
+ "ENOTFOUND",
36
+ "EAI_AGAIN",
37
+ "ENETUNREACH",
38
+ "ENETDOWN",
39
+ "EHOSTUNREACH",
40
+ ]);
41
+
42
+ /** Upper bound on how far `cause` chains are inspected. */
43
+ export const MAX_REACHABILITY_CAUSE_DEPTH = 3;
44
+
45
+ /**
46
+ * True when the rejection (or a bounded `cause` of it) carries a proven
47
+ * pre-connection reachability code. Never matches message text.
48
+ */
49
+ export function isPreConnectReachabilityError(err: unknown): boolean {
50
+ let current: unknown = err;
51
+ const seen = new Set<unknown>();
52
+ for (let depth = 0; depth < MAX_REACHABILITY_CAUSE_DEPTH; depth++) {
53
+ if (!(current instanceof Error) || seen.has(current)) return false;
54
+ seen.add(current);
55
+ const code = (current as { code?: unknown }).code;
56
+ if (typeof code === "string" && PRE_CONNECT_REACHABILITY_CODES.has(code)) return true;
57
+ current = current.cause;
58
+ }
59
+ return false;
60
+ }
61
+
62
+ export type TransportFailureKind = "timeout" | "connect_neutral" | "connect_error";
63
+
64
+ /**
65
+ * Shared transport rejection classification for Codex pool upstream sends.
66
+ * Timeouts keep their existing identity (account-transient); proven pre-connect
67
+ * reachability failures become account-neutral; everything else (ECONNRESET,
68
+ * EPIPE, TLS, unknown shapes) keeps the existing `connect_error`
69
+ * account-attributed behavior.
70
+ */
71
+ export function classifyTransportFailureKind(err: unknown): TransportFailureKind {
72
+ // A local pacing admission failure happened before transport classification and must
73
+ // remain a client-visible overload, not account or host health evidence.
74
+ if (err instanceof RequestPacingQueueOverloadError) throw err;
75
+ const evidence = err instanceof UpstreamRetryEvidenceError ? err : undefined;
76
+ const rejection = evidence ? evidence.cause : err;
77
+ if (rejection instanceof Error && rejection.name === "TimeoutError") return "timeout";
78
+ if (isPreConnectReachabilityError(rejection)) {
79
+ // A transient upstream response (5xx) or a credential-visible connection
80
+ // reset before the rejection proves the host and credential path were
81
+ // reached: the failure is account-attributable, never the pre-connection
82
+ // neutral class (issue #914 review).
83
+ if (evidence && (evidence.transientStatuses.length > 0 || evidence.resetSeen)) return "connect_error";
84
+ return "connect_neutral";
85
+ }
86
+ return "connect_error";
87
+ }
88
+
89
+ /** Stable `code` carried by a transport rejection, when there is one. */
90
+ export function transportErrorCode(err: unknown): string | undefined {
91
+ const rejection = err instanceof UpstreamRetryEvidenceError ? err.cause : err;
92
+ if (!(rejection instanceof Error)) return undefined;
93
+ const code = (rejection as { code?: unknown }).code;
94
+ return typeof code === "string" && code !== "" ? code : undefined;
95
+ }