@iislee/opencodex 2.11.0 → 2.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -0,0 +1,637 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { execFile as execFileCallback } from "node:child_process";
3
+ import { promisify } from "node:util";
4
+ import { opendir } from "node:fs/promises";
5
+ import type { AdapterEvent, OcxContentPart, OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxTool, OcxUsage } from "../types";
6
+ import { isAllowedToolChoice, namespacedToolName, resolveToolChoiceWireName, toolChoiceToolPredicate } from "../types";
7
+ import type { AdapterFetchContext, AdapterRequest, ProviderAdapter } from "./base";
8
+ import type { TranslatorBudget } from "../lib/translator-budget";
9
+ import { readBoundedResponseBody } from "../lib/bounded-body";
10
+ import { debugDroppedFrame } from "../lib/debug";
11
+ import { configuredReasoningEfforts } from "../reasoning-effort";
12
+ import { commandCodeReasoningEfforts, refreshCommandCodeReasoningEfforts } from "../providers/command-code-efforts";
13
+ import { identifyRoutedModel } from "./identity";
14
+ import { buildNonOpenAIToolCatalogNudgeForTools } from "./tool-catalog-nudge";
15
+ import { parseDataUrl } from "./image";
16
+
17
+ // Retain the short ids emitted by the first local integration. New requests use the live catalog's
18
+ // provider-native IDs directly; this map is compatibility-only and is not a model fallback list.
19
+ const COMMAND_CODE_MODEL_ALIASES: Readonly<Record<string, string>> = {
20
+ "deepseek-v4-flash": "deepseek/deepseek-v4-flash",
21
+ "kimi-k3": "moonshotai/Kimi-K3",
22
+ "glm-5.3": "zai-org/GLM-5.3",
23
+ "glm-5.2": "zai-org/GLM-5.2",
24
+ };
25
+
26
+ function canonicalCommandCodeModelId(modelId: string): string {
27
+ return Object.hasOwn(COMMAND_CODE_MODEL_ALIASES, modelId) ? COMMAND_CODE_MODEL_ALIASES[modelId]! : modelId;
28
+ }
29
+
30
+ /** Flatten tool-result content for the text-only wire output, keeping an `[image]` marker per image part in content order. */
31
+ function toolResultText(content: string | OcxContentPart[]): string {
32
+ if (typeof content === "string") return content;
33
+ return content.map(part => (part.type === "text" ? part.text : "[image]")).join("");
34
+ }
35
+
36
+ /** Best-effort media type from a remote https URL extension, e.g. image/png. */
37
+ function mediaTypeFromUrl(url: string): string | undefined {
38
+ const ext = url.split(/[?#]/)[0]!.match(/\.([a-zA-Z0-9]+)$/)?.[1]?.toLowerCase();
39
+ if (!ext) return undefined;
40
+ const known: Record<string, string> = {
41
+ png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", gif: "image/gif", webp: "image/webp", bmp: "image/bmp",
42
+ };
43
+ return known[ext];
44
+ }
45
+
46
+ /** Wire image part: `{ type, image, mediaType? }` per the /alpha/generate ModelMessage schema. */
47
+ function wireImagePart(imageUrl: string): Record<string, unknown> {
48
+ const parsed = parseDataUrl(imageUrl);
49
+ const mediaType = parsed?.mediaType ?? mediaTypeFromUrl(imageUrl);
50
+ return { type: "image", image: imageUrl, ...(mediaType ? { mediaType } : {}) };
51
+ }
52
+
53
+ /**
54
+ * The /alpha/generate wire pairs every assistant `tool-call` with a following `tool` message
55
+ * whose `tool-result.toolCallId` matches it. Codex history is not guaranteed to carry that
56
+ * pairing (interrupted turns, compacted threads, and multi-step tool rounds all can leave an
57
+ * assistant call with no recorded result), and the upstream rejects an unpaired call with
58
+ * `Tool result is missing for tool call <id>`, which currently surfaces as a generic 502
59
+ * (#1383). This builder keeps the pairing invariant:
60
+ *
61
+ * - a `toolResult` that matches a declared assistant call emits the native `tool-result`;
62
+ * - a `toolResult` with no matching declared call degrades to a text carrier so the model
63
+ * still sees the outcome without a 400-prone standalone `tool` message;
64
+ * - every declared assistant call that never received a result gets an explicit error
65
+ * `tool-result`, so the upstream never sees an unpaired call.
66
+ */
67
+ function wireMessages(messages: OcxMessage[]): Array<Record<string, unknown>> {
68
+ const out: Array<Record<string, unknown>> = [];
69
+ const pendingCalls: Array<{ id: string; name: string }> = [];
70
+ // Image parts returned by a tool cannot live inside the text-only `tool-result` wire
71
+ // output. They ride a follow-up user message, but that user message must not break the
72
+ // adjacency of the assistant turn's tool results, so carriers are buffered and flushed
73
+ // only after every declared call has its native or synthesized result.
74
+ const pendingImageCarriers: Array<Record<string, unknown>> = [];
75
+ // The /alpha/generate wire requires every assistant tool-call to be closed by a matching
76
+ // `tool-result` immediately after the declaring assistant message. Close any declared call
77
+ // that never received a result before a non-toolResult message moves the turn forward, so a
78
+ // synthesized `tool` message never lands after a user message or a new assistant turn.
79
+ const closePendingCalls = (): void => {
80
+ for (const call of pendingCalls) {
81
+ out.push({ role: "tool", content: [{
82
+ type: "tool-result",
83
+ toolCallId: call.id,
84
+ toolName: call.name,
85
+ output: { type: "error-text", value: "[ocx] no tool result was recorded for this tool call; execution status unknown." },
86
+ }] });
87
+ }
88
+ pendingCalls.length = 0;
89
+ if (pendingImageCarriers.length > 0) {
90
+ out.push(...pendingImageCarriers);
91
+ pendingImageCarriers.length = 0;
92
+ }
93
+ };
94
+ for (const message of messages) {
95
+ if (message.role === "assistant") {
96
+ closePendingCalls();
97
+ const content: Array<Record<string, unknown>> = [];
98
+ for (const part of message.content) {
99
+ if (part.type === "text") content.push({ type: "text", text: part.text });
100
+ else if (part.type === "thinking") content.push({ type: "reasoning", text: part.thinking });
101
+ else {
102
+ const wireName = namespacedToolName(part.namespace, part.name);
103
+ content.push({ type: "tool-call", toolCallId: part.id, toolName: wireName, input: part.arguments });
104
+ pendingCalls.push({ id: part.id, name: wireName });
105
+ }
106
+ }
107
+ out.push({ role: "assistant", content });
108
+ continue;
109
+ }
110
+ if (message.role === "toolResult") {
111
+ const callIndex = pendingCalls.findIndex(call => call.id === message.toolCallId);
112
+ const paired = callIndex >= 0;
113
+ if (paired) pendingCalls.splice(callIndex, 1);
114
+ if (!paired) {
115
+ // Pending calls from an earlier assistant turn must still be closed before any user
116
+ // message lands, or their synthesized results would follow the orphan carrier.
117
+ closePendingCalls();
118
+ // The upstream rejects a standalone tool message whose call was never declared by an
119
+ // assistant turn. Preserve the outcome as text so the model can still act on it.
120
+ const label = message.toolName ? `${message.toolName} (${message.toolCallId})` : message.toolCallId;
121
+ const text = toolResultText(message.content);
122
+ // The orphan result cannot ride a `tool` message; carry it in a user message instead.
123
+ out.push({ role: "user", content: [{ type: "text", text: `[tool result without adjacent tool call: ${label}]\n${text}` }] });
124
+ continue;
125
+ }
126
+ out.push({ role: "tool", content: [{
127
+ type: "tool-result",
128
+ toolCallId: message.toolCallId,
129
+ toolName: namespacedToolName(message.toolNamespace, message.toolName),
130
+ output: { type: message.isError ? "error-text" : "text", value: toolResultText(message.content) },
131
+ }] });
132
+ // The proprietary wire's tool-result output is text-only; image parts returned by a
133
+ // tool (e.g. Codex view_image) cannot live inside it. Carry them in a follow-up user
134
+ // message using the same image encoding as the user branch so the bytes reach the model.
135
+ const images = typeof message.content === "string" ? [] : message.content.filter(part => part.type === "image");
136
+ if (images.length > 0) {
137
+ pendingImageCarriers.push({ role: "user", content: images.map(part => wireImagePart((part as { imageUrl: string }).imageUrl)) });
138
+ }
139
+ continue;
140
+ }
141
+ // User/developer message: no pending tool results may follow it on the wire.
142
+ closePendingCalls();
143
+ const content: Array<Record<string, unknown>> = [];
144
+ if (typeof message.content === "string") content.push({ type: "text", text: message.content });
145
+ else for (const part of message.content) {
146
+ if (part.type === "text") content.push({ type: "text", text: part.text });
147
+ else if (part.type === "image") content.push(wireImagePart(part.imageUrl));
148
+ else content.push({ type: "text", text: "[video]" });
149
+ }
150
+ out.push({ role: "user", content });
151
+ }
152
+ closePendingCalls();
153
+ return out;
154
+ }
155
+
156
+ function visibleTools(parsed: OcxParsedRequest): OcxTool[] {
157
+ const choice = parsed.options.toolChoice;
158
+ if (choice === "none") return [];
159
+ const tools = parsed.context.tools ?? [];
160
+ if (isAllowedToolChoice(choice)) {
161
+ return tools.filter(toolChoiceToolPredicate(choice, tools));
162
+ }
163
+ if (choice && typeof choice !== "string") {
164
+ const selected = resolveToolChoiceWireName(tools, choice.name);
165
+ return tools.filter(tool => namespacedToolName(tool.namespace, tool.name) === selected);
166
+ }
167
+ return tools;
168
+ }
169
+
170
+ function toolChoiceInstruction(parsed: OcxParsedRequest): string | undefined {
171
+ const choice = parsed.options.toolChoice;
172
+ if (choice === "required" || (isAllowedToolChoice(choice) && choice.mode === "required")) {
173
+ return "Tool choice is required for this turn. Make at least one call from the advertised tool catalog before answering.";
174
+ }
175
+ if (choice && typeof choice !== "string" && !isAllowedToolChoice(choice)) {
176
+ // Resolve the forced name (bare, namespace__name, or namespace.name) to the advertised
177
+ // wire name so the instruction names a tool that is actually in the catalog.
178
+ const wireName = resolveToolChoiceWireName(parsed.context.tools, choice.name);
179
+ return `Tool choice is required for this turn. Call the advertised tool named ${wireName} before answering.`;
180
+ }
181
+ return undefined;
182
+ }
183
+
184
+ function wireTools(tools: OcxTool[]): Array<Record<string, unknown>> {
185
+ return tools.map(tool => ({
186
+ name: namespacedToolName(tool.namespace, tool.name),
187
+ description: tool.description,
188
+ input_schema: tool.parameters,
189
+ }));
190
+ }
191
+
192
+ function currentWorkingDirectory(): string | undefined {
193
+ try { return process.cwd(); } catch { return undefined; }
194
+ }
195
+
196
+ /** Cap the workspace listing so a large directory does not ship every entry name upstream. */
197
+ const MAX_WORKSPACE_STRUCTURE_ENTRIES = 64;
198
+ /** Cap how many recent commit subjects the config carries. */
199
+ const MAX_RECENT_COMMITS = 8;
200
+ /** Cap each recent commit entry to keep the request bounded even for long subjects. */
201
+ const MAX_RECENT_COMMIT_LENGTH = 512;
202
+ /** Cap the git status text sent upstream. */
203
+ const MAX_GIT_STATUS_LENGTH = 2048;
204
+ /** Keep collected workspace/git metadata fresh for this long (ms) so repeated requests reuse it. */
205
+ const WORKSPACE_METADATA_TTL_MS = 30_000;
206
+ /** Hard cap on cached workspace metadata entries to prevent unbounded growth across distinct cwds. */
207
+ export const MAX_WORKSPACE_METADATA_ENTRIES = 128;
208
+
209
+ /** Derive a bounded project slug from the working directory for the `x-project-slug` header. */
210
+ function projectSlug(cwd: string): string {
211
+ return cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "").toLowerCase().slice(0, 64) || "workspace";
212
+ }
213
+
214
+ interface GitWorkspaceInfo {
215
+ isGitRepo: boolean;
216
+ currentBranch: string;
217
+ mainBranch: string;
218
+ gitStatus: string;
219
+ recentCommits: string[];
220
+ }
221
+
222
+ export const workspaceMetadataCache = new Map<string, { collectedAt: number; value: GitWorkspaceInfo }>();
223
+
224
+ /**
225
+ * Evict expired entries first, then the oldest live entry if at capacity.
226
+ * Called before inserting a new key so the cache never exceeds the cap.
227
+ */
228
+ export function pruneWorkspaceMetadataCache(now: number): void {
229
+ // Pass 1: remove expired entries.
230
+ for (const [key, entry] of workspaceMetadataCache) {
231
+ if (now - entry.collectedAt >= WORKSPACE_METADATA_TTL_MS) {
232
+ workspaceMetadataCache.delete(key);
233
+ }
234
+ }
235
+ // Pass 2: if still at capacity, evict the oldest live entry.
236
+ if (workspaceMetadataCache.size >= MAX_WORKSPACE_METADATA_ENTRIES) {
237
+ let oldestKey: string | null = null;
238
+ let oldestAt = Infinity;
239
+ for (const [key, entry] of workspaceMetadataCache) {
240
+ if (entry.collectedAt < oldestAt) {
241
+ oldestAt = entry.collectedAt;
242
+ oldestKey = key;
243
+ }
244
+ }
245
+ if (oldestKey !== null) workspaceMetadataCache.delete(oldestKey);
246
+ }
247
+ }
248
+
249
+ const execFile = promisify(execFileCallback);
250
+
251
+ /** Best-effort git metadata for the upstream config contract; every read fails safe and stays off the event loop. */
252
+ async function gitWorkspaceInfo(cwd: string | undefined): Promise<GitWorkspaceInfo> {
253
+ const fallback: GitWorkspaceInfo = { isGitRepo: false, currentBranch: "", mainBranch: "", gitStatus: "", recentCommits: [] };
254
+ if (!cwd) return fallback;
255
+ const cached = workspaceMetadataCache.get(cwd);
256
+ if (cached && Date.now() - cached.collectedAt < WORKSPACE_METADATA_TTL_MS) return cached.value;
257
+ const run = async (args: string[]): Promise<string> => {
258
+ try {
259
+ const { stdout } = await execFile("git", args, { cwd, encoding: "utf8", timeout: 2000, windowsHide: true });
260
+ return stdout.trim();
261
+ } catch {
262
+ return "";
263
+ }
264
+ };
265
+ const root = await run(["rev-parse", "--show-toplevel"]);
266
+ const value = root
267
+ ? {
268
+ isGitRepo: true,
269
+ currentBranch: (await run(["rev-parse", "--abbrev-ref", "HEAD"])) || "HEAD",
270
+ mainBranch: (await run(["symbolic-ref", "--short", "refs/remotes/origin/HEAD"])).replace(/^origin\//, "") || (await run(["rev-parse", "--abbrev-ref", "HEAD"])) || "",
271
+ gitStatus: (await run(["status", "--porcelain"])).slice(0, MAX_GIT_STATUS_LENGTH),
272
+ recentCommits: (await run(["log", "--oneline", `-${MAX_RECENT_COMMITS}`]))
273
+ .split("\n")
274
+ .filter(Boolean)
275
+ .slice(0, MAX_RECENT_COMMITS)
276
+ .map(commit => commit.slice(0, MAX_RECENT_COMMIT_LENGTH)),
277
+ }
278
+ : fallback;
279
+ const now = Date.now();
280
+ if (!workspaceMetadataCache.has(cwd)) pruneWorkspaceMetadataCache(now);
281
+ workspaceMetadataCache.set(cwd, { collectedAt: now, value });
282
+ return value;
283
+ }
284
+
285
+ async function commandCodeConfig(cwd: string | undefined): Promise<Record<string, unknown>> {
286
+ let structure: string[] = [];
287
+ if (cwd) {
288
+ try {
289
+ // Iterate and stop after the cap instead of materializing every entry: a directory with a
290
+ // huge number of names must not stall the request path for 64 metadata rows.
291
+ const dir = await opendir(cwd);
292
+ try {
293
+ for await (const entry of dir) {
294
+ if (entry.name.startsWith(".")) continue;
295
+ structure.push(entry.name);
296
+ if (structure.length >= MAX_WORKSPACE_STRUCTURE_ENTRIES) break;
297
+ }
298
+ } finally {
299
+ await dir.close().catch(() => undefined);
300
+ }
301
+ } catch { /* workspace metadata is optional */ }
302
+ }
303
+ const git = await gitWorkspaceInfo(cwd);
304
+ return {
305
+ ...(cwd ? { workingDir: cwd } : {}),
306
+ date: new Date().toISOString().slice(0, 10),
307
+ environment: process.platform,
308
+ structure,
309
+ ...git,
310
+ };
311
+ }
312
+
313
+ function usage(value: unknown): OcxUsage | undefined {
314
+ if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
315
+ const row = value as Record<string, unknown>;
316
+ const inputTokens = typeof row.inputTokens === "number" ? row.inputTokens : 0;
317
+ const outputTokens = typeof row.outputTokens === "number" ? row.outputTokens : 0;
318
+ const details = row.inputTokenDetails && typeof row.inputTokenDetails === "object" && !Array.isArray(row.inputTokenDetails)
319
+ ? row.inputTokenDetails as Record<string, unknown> : {};
320
+ const cachedInputTokens = typeof details.cacheReadTokens === "number" ? details.cacheReadTokens : undefined;
321
+ const cacheCreationInputTokens = typeof details.cacheWriteTokens === "number" ? details.cacheWriteTokens : undefined;
322
+ return {
323
+ inputTokens, outputTokens, totalTokens: inputTokens + outputTokens,
324
+ ...(cachedInputTokens !== undefined ? { cachedInputTokens, cacheReadInputTokens: cachedInputTokens } : {}),
325
+ ...(cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens } : {}),
326
+ };
327
+ }
328
+
329
+ function eventError(value: unknown): string {
330
+ if (typeof value === "string" && value) return value;
331
+ if (value && typeof value === "object" && !Array.isArray(value)) {
332
+ const message = (value as Record<string, unknown>).message;
333
+ if (typeof message === "string" && message) return message;
334
+ }
335
+ return "Command Code stream error";
336
+ }
337
+
338
+ /**
339
+ * True when the upstream rejected a tool-result continuation because an assistant tool call
340
+ * had no matching result (`Tool result is missing for tool call <id>`). The proxy now keeps
341
+ * that pairing invariant before sending, so this error is a distinct provider-side
342
+ * validation failure rather than a generic stream fault; classify it as such for the
343
+ * dashboard/logs instead of a plain upstream 502.
344
+ */
345
+ function isMissingToolResultError(value: unknown): boolean {
346
+ const text = eventError(value).toLowerCase();
347
+ return text.includes("tool result is missing") || text.includes("tool_result is missing");
348
+ }
349
+
350
+ async function*ndjson(response: Response, budget: TranslatorBudget): AsyncGenerator<Record<string, unknown>> {
351
+ if (!response.body) throw new Error("Command Code response body missing");
352
+ const reader = response.body.getReader();
353
+ const decoder = new TextDecoder();
354
+ const encoder = new TextEncoder();
355
+ let buffer = "";
356
+ let bufferBytes = 0;
357
+ try {
358
+ for (;;) {
359
+ const { value, done } = await reader.read();
360
+ const next = buffer + decoder.decode(value, { stream: !done });
361
+ const nextBytes = encoder.encode(next).byteLength;
362
+ const reservation = budget.reserveTransient(nextBytes, { kind: "live_transient" });
363
+ buffer = next;
364
+ reservation.commitRetained();
365
+ budget.releaseRetained(bufferBytes, { kind: "live_transient" });
366
+ bufferBytes = nextBytes;
367
+ let newline = buffer.indexOf("\n");
368
+ while (newline >= 0) {
369
+ const line = buffer.slice(0, newline).trim(); buffer = buffer.slice(newline + 1);
370
+ if (line) yield* decodeEventLine(line);
371
+ newline = buffer.indexOf("\n");
372
+ }
373
+ const residualBytes = encoder.encode(buffer).byteLength;
374
+ const residualReservation = budget.reserveTransient(residualBytes, { kind: "live_transient" });
375
+ residualReservation.commitRetained();
376
+ budget.releaseRetained(bufferBytes, { kind: "live_transient" });
377
+ bufferBytes = residualBytes;
378
+ if (done) break;
379
+ }
380
+ const final = buffer.trim();
381
+ if (final) yield* decodeEventLine(final);
382
+ } finally {
383
+ budget.releaseRetained(bufferBytes, { kind: "live_transient" });
384
+ try { await reader.cancel(); } catch { /* already closed */ }
385
+ reader.releaseLock();
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Yield one NDJSON line as an event record, or nothing.
391
+ *
392
+ * `JSON.parse("null")` returns `null` instead of throwing, so the `try/catch` around the parse
393
+ * cannot see it and the `event.type` read in parseStream crashed the turn — the #1219 defect, on
394
+ * the one streaming transport the #1240 audit did not cover because it is NDJSON rather than SSE.
395
+ *
396
+ * A frame that does not parse to a record is padding, not an event: drop it and continue exactly
397
+ * as an unparseable line is already dropped, so a stream whose only frames are junk ends in the
398
+ * same single terminal `done` as an empty body. Skipping is what preserves an answer whose deltas
399
+ * have already arrived — the observed #1219 case is `null` padding BETWEEN content deltas, where
400
+ * terminating would discard a complete response (#1240).
401
+ *
402
+ * Note this deliberately makes a junk-only stream a quiet `[done]` where it previously threw. That
403
+ * throw was an unguarded type assumption, not a designed failure signal, and `[done]` is already
404
+ * what an empty body, a blank-line-only body and an unparseable-only body all produce here. The
405
+ * broader question — whether this adapter should report *any* no-valid-event stream as a failure
406
+ * rather than an empty success — is pre-existing, applies to all four of those inputs equally, and
407
+ * is deliberately not decided by this change.
408
+ */
409
+ function* decodeEventLine(line: string): Generator<Record<string, unknown>> {
410
+ let parsed: unknown;
411
+ try {
412
+ parsed = JSON.parse(stripEventFrame(line));
413
+ } catch {
414
+ debugDroppedFrame("command-code", line);
415
+ return;
416
+ }
417
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
418
+ debugDroppedFrame("command-code", line);
419
+ return;
420
+ }
421
+ yield parsed as Record<string, unknown>;
422
+ }
423
+
424
+ /** The endpoint is newline-delimited JSON; defensively strip an SSE `data:` frame if the gateway ever switches shapes. */
425
+ function stripEventFrame(line: string): string {
426
+ return line.startsWith("data:") ? line.slice("data:".length).trim() : line;
427
+ }
428
+
429
+ function isReasoningEffortRejection(status: number, payload: string): boolean {
430
+ return (status === 400 || status === 422) && /reasoning[_ -]?effort|unsupported effort|invalid effort/i.test(payload);
431
+ }
432
+
433
+ function requestWithoutReasoningEffort(request: AdapterRequest): AdapterRequest | undefined {
434
+ try {
435
+ const body = JSON.parse(request.body) as { params?: Record<string, unknown> };
436
+ if (!body.params?.reasoning_effort) return undefined;
437
+ delete body.params.reasoning_effort;
438
+ return { ...request, body: JSON.stringify(body), reasoningLog: undefined };
439
+ } catch {
440
+ return undefined;
441
+ }
442
+ }
443
+
444
+ async function fetchCommandCode(request: AdapterRequest, ctx: AdapterFetchContext | undefined, executor: typeof globalThis.fetch): Promise<Response> {
445
+ const timeout = new AbortController();
446
+ const timer = setTimeout(() => timeout.abort(new DOMException("Timeout elapsed", "TimeoutError")), ctx?.timeoutMs ?? 200_000);
447
+ const callerSignal = ctx?.abortSignal ?? new AbortController().signal;
448
+ try {
449
+ return await executor(request.url, {
450
+ method: request.method,
451
+ headers: request.headers,
452
+ body: request.body,
453
+ redirect: "manual",
454
+ signal: AbortSignal.any([callerSignal, timeout.signal]),
455
+ });
456
+ } finally {
457
+ clearTimeout(timer);
458
+ }
459
+ }
460
+
461
+ function supportedCommandCodeEffort(provider: OcxProviderConfig, modelId: string, requested: string | undefined): string | undefined {
462
+ if (!requested || requested === "none") return undefined;
463
+ // Compatibility ids (deepseek-v4-flash / glm-5.2) must resolve to their canonical
464
+ // Command Code id before the effort lookup, or legacy requests silently lose the
465
+ // reasoning effort because the official table is keyed by the canonical ids.
466
+ const canonicalId = canonicalCommandCodeModelId(modelId);
467
+ const supported = commandCodeReasoningEfforts(canonicalId) ?? configuredReasoningEfforts(provider, canonicalId);
468
+ if (!supported) return undefined;
469
+ // Only remap xhigh/ultra→max for models whose official profile documents that
470
+ // aliasing (deepseek v4, glm-5.2). Muse Spark's upstream accepts xhigh as a
471
+ // distinct wire value and rejects ultra, so it must not be collapsed.
472
+ let wire = requested;
473
+ const lower = canonicalId.toLowerCase();
474
+ const needsAlias =
475
+ lower === "deepseek/deepseek-v4-pro" ||
476
+ lower === "deepseek/deepseek-v4-flash" ||
477
+ lower === "zai-org/glm-5.2";
478
+ if (requested === "xhigh" && !supported.includes("xhigh") && supported.includes("max")) {
479
+ wire = "max";
480
+ } else if (requested === "ultra" && needsAlias && supported.includes("max")) {
481
+ wire = "max";
482
+ }
483
+ return (supported as readonly string[]).includes(wire) ? wire : undefined;
484
+ }
485
+
486
+ export function createCommandCodeAdapter(provider: OcxProviderConfig): ProviderAdapter {
487
+ const executor = (provider as OcxProviderConfig & { fetch?: typeof globalThis.fetch }).fetch ?? globalThis.fetch;
488
+ return {
489
+ name: "command-code",
490
+ async buildRequest(parsed: OcxParsedRequest): Promise<AdapterRequest> {
491
+ if (!provider.apiKey) throw new Error("Command Code credential missing — run ocx login command-code");
492
+ const cwd = currentWorkingDirectory();
493
+ const tools = visibleTools(parsed);
494
+ const toolNudge = buildNonOpenAIToolCatalogNudgeForTools(tools, parsed.options.toolChoice);
495
+ const choiceInstruction = toolChoiceInstruction(parsed);
496
+ const system = identifyRoutedModel([
497
+ ...(parsed.context.systemPrompt ?? []),
498
+ ...(toolNudge ? [toolNudge] : []),
499
+ ...(choiceInstruction ? [choiceInstruction] : []),
500
+ ].join("\n\n"), parsed.modelId);
501
+ const reasoningEffort = supportedCommandCodeEffort(provider, parsed.modelId, parsed.options.reasoning);
502
+ const body = {
503
+ config: await commandCodeConfig(cwd), memory: "", taste: null, skills: null,
504
+ permissionMode: "standard", mode: "agent",
505
+ params: {
506
+ model: canonicalCommandCodeModelId(parsed.modelId),
507
+ messages: wireMessages(parsed.context.messages),
508
+ tools: wireTools(tools),
509
+ system,
510
+ max_tokens: parsed.options.maxOutputTokens ?? provider.defaultMaxOutputTokens ?? 64_000,
511
+ // The proprietary /alpha/generate endpoint is NDJSON-stream-only; the proxy converts
512
+ // the buffered/streamed events to the client's requested shape (parsed.stream).
513
+ stream: true,
514
+ ...(parsed.options.temperature !== undefined ? { temperature: parsed.options.temperature } : {}),
515
+ ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),
516
+ },
517
+ };
518
+ const headers: Record<string, string> = {
519
+ Authorization: `Bearer ${provider.apiKey}`,
520
+ "Content-Type": "application/json",
521
+ "User-Agent": "cli",
522
+ "x-command-code-version": provider.commandCodeVersion ?? "0.52.1",
523
+ "x-cli-environment": "production",
524
+ "x-taste-learning": "false",
525
+ "x-co-flag": "false",
526
+ "x-session-id": randomUUID(),
527
+ };
528
+ if (cwd) headers["x-project-slug"] = projectSlug(cwd);
529
+ return {
530
+ url: `${provider.baseUrl.replace(/\/$/, "")}/alpha/generate`, method: "POST",
531
+ headers,
532
+ body: JSON.stringify(body),
533
+ ...(reasoningEffort ? { reasoningLog: { effectiveEffort: reasoningEffort, wireField: "reasoning_effort" as const, wireValue: reasoningEffort } } : {}),
534
+ };
535
+ },
536
+ async fetchResponse(request: AdapterRequest, ctx?: AdapterFetchContext): Promise<Response> {
537
+ const response = await fetchCommandCode(request, ctx, executor);
538
+ if (response.ok) return response;
539
+ const currentEffort = (() => {
540
+ try { return (JSON.parse(request.body) as { params?: { reasoning_effort?: unknown } }).params?.reasoning_effort; } catch { return undefined; }
541
+ })();
542
+ if (typeof currentEffort !== "string") return response;
543
+ let body = "";
544
+ try {
545
+ const observed = await readBoundedResponseBody(response.clone(), { signal: ctx?.abortSignal, maxBytes: 8 * 1024 });
546
+ if (!observed.displaySafe) return response;
547
+ body = observed.text;
548
+ } catch { return response; }
549
+ if (!isReasoningEffortRejection(response.status, body)) return response;
550
+ const modelId = (() => {
551
+ try { return (JSON.parse(request.body) as { params?: { model?: unknown } }).params?.model; } catch { return undefined; }
552
+ })();
553
+ if (typeof modelId !== "string") return response;
554
+ const refreshed = await refreshCommandCodeReasoningEfforts(modelId, executor);
555
+ if (!refreshed || refreshed.includes(currentEffort)) return response;
556
+ const retry = requestWithoutReasoningEffort(request);
557
+ if (!retry) return response;
558
+ try { void response.body?.cancel(); } catch { /* already closed */ }
559
+ return fetchCommandCode(retry, ctx, executor);
560
+ },
561
+ async *parseStream(response: Response, budget: TranslatorBudget): AsyncGenerator<AdapterEvent> {
562
+ let sawFinish = false;
563
+ for await (const event of ndjson(response, budget)) {
564
+ switch (event.type) {
565
+ case "text-delta": if (typeof event.text === "string") yield { type: "text_delta", text: event.text }; break;
566
+ case "reasoning-delta": if (typeof event.text === "string") yield { type: "thinking_delta", thinking: event.text }; break;
567
+ case "tool-call": {
568
+ const id = typeof event.toolCallId === "string" ? event.toolCallId : randomUUID();
569
+ const name = typeof event.toolName === "string" ? event.toolName : "tool";
570
+ const input = event.input ?? event.args ?? {};
571
+ const argumentsText = typeof input === "string" ? input : JSON.stringify(input);
572
+ yield { type: "tool_call_start", id, name };
573
+ budget.openCall(id);
574
+ try {
575
+ const reservation = budget.reserveTransient(new TextEncoder().encode(argumentsText).byteLength, { kind: "tool_args", callId: id });
576
+ reservation.commitRetained();
577
+ yield { type: "tool_call_delta", arguments: argumentsText };
578
+ yield { type: "tool_call_end" };
579
+ } finally {
580
+ budget.closeCall(id);
581
+ }
582
+ break;
583
+ }
584
+ case "finish-step":
585
+ case "finish": {
586
+ // Both events are terminal on the current wire; streams commonly carry both, so
587
+ // only the first one emits the done. finish-step carries `usage`; finish may carry
588
+ // `totalUsage` (current flows) or `usage`.
589
+ if (sawFinish) break;
590
+ sawFinish = true;
591
+ const usageValue = event.totalUsage ?? event.usage;
592
+ const stopReason = typeof event.rawFinishReason === "string" ? event.rawFinishReason : typeof event.finishReason === "string" ? event.finishReason : undefined;
593
+ // The AI SDK's `error` finish reason means the generation failed upstream, not that it
594
+ // stopped. Reporting it as a `done` left the bridge to infer failure from a stop-reason
595
+ // string, which either read as a clean completion or (once classified) mislabelled an
596
+ // upstream error as a content filter and rejected it from the replay cache for the
597
+ // wrong reason.
598
+ if (stopReason === "error") {
599
+ // Keep the usage: a failed turn still consumed tokens, and dropping it makes the
600
+ // turn look free in accounting and reports zeros to the client.
601
+ yield {
602
+ type: "error",
603
+ message: "Command Code upstream ended the turn with finishReason \"error\"",
604
+ status: 502,
605
+ errorType: "upstream_error",
606
+ usage: usage(usageValue),
607
+ };
608
+ break;
609
+ }
610
+ yield { type: "done", usage: usage(usageValue), stopReason };
611
+ break;
612
+ }
613
+ case "error": {
614
+ const message = eventError(event.error);
615
+ if (isMissingToolResultError(message)) {
616
+ // Provider-side tool-result validation: the request carried an assistant tool
617
+ // call the upstream refused to accept. This is not a network/stream stall; the
618
+ // proxy normally prevents it by pairing every call, so flag it distinctly.
619
+ yield { type: "error", message, status: 502, errorType: "upstream_error", code: "missing_tool_result" };
620
+ } else {
621
+ yield { type: "error", message, status: 502 };
622
+ }
623
+ break;
624
+ }
625
+ }
626
+ }
627
+ // A stream that ends without a finish event still needs a terminal done so the
628
+ // server does not wait on an adapter that silently stopped emitting.
629
+ if (!sawFinish) yield { type: "done", usage: undefined, stopReason: undefined };
630
+ },
631
+ async parseResponse(response: Response, budget: TranslatorBudget): Promise<AdapterEvent[]> {
632
+ const events: AdapterEvent[] = [];
633
+ for await (const event of this.parseStream(response, budget)) events.push(event);
634
+ return events;
635
+ },
636
+ };
637
+ }