@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,175 @@
1
+ import { createAnthropicAdapter } from "./anthropic";
2
+ import { createAzureAdapter } from "./azure";
3
+ import type { ProviderAdapter } from "./base";
4
+ import { withClinePassDeepSeekV4ToolReplayCompatibility } from "./cline-pass-deepseek-v4-tool-replay";
5
+ import { createCommandCodeAdapter } from "./command-code";
6
+ import { createCursorAdapter } from "./cursor";
7
+ import { createGoogleAdapter } from "./google";
8
+ import { createKiroAdapter } from "./kiro";
9
+ import { createMimoFreeAdapter } from "./mimo-free";
10
+ import { createOpenAIChatAdapter } from "./openai-chat";
11
+ import { createResponsesPassthroughAdapter } from "./openai-responses";
12
+ import type { OcxProviderConfig } from "../types";
13
+ import { createAdapterTierMetadata } from "../providers/fastwire";
14
+
15
+ export type AdapterCacheRetention = "none" | "short" | "long";
16
+
17
+ export interface AdapterFactoryContext {
18
+ cacheRetention?: AdapterCacheRetention;
19
+ }
20
+
21
+ export type AdapterWire =
22
+ | "command-code"
23
+ | "openai-chat"
24
+ | "anthropic"
25
+ | "openai-responses"
26
+ | "google"
27
+ | "kiro"
28
+ | "cursor";
29
+
30
+ export type AdapterMutationContract =
31
+ | "codex-owned"
32
+ | "codex-owned-with-gated-native-fallback";
33
+
34
+ type AdapterFactory = (
35
+ provider: OcxProviderConfig,
36
+ context: AdapterFactoryContext,
37
+ ) => ProviderAdapter;
38
+
39
+ type DirectAdapterDefinition = {
40
+ wire: AdapterWire;
41
+ mutation: AdapterMutationContract;
42
+ create: AdapterFactory;
43
+ };
44
+
45
+ type InheritedAdapterDefinition = {
46
+ /** Semantic contract inheritance only. Runtime construction remains independent. */
47
+ contractParent: string;
48
+ create: AdapterFactory;
49
+ };
50
+
51
+ type AdapterDefinition = DirectAdapterDefinition | InheritedAdapterDefinition;
52
+
53
+ export const ADAPTER_REGISTRY = {
54
+ "command-code": {
55
+ wire: "command-code",
56
+ mutation: "codex-owned",
57
+ create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) => createCommandCodeAdapter(provider),
58
+ },
59
+ "openai-chat": {
60
+ wire: "openai-chat",
61
+ mutation: "codex-owned",
62
+ create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) =>
63
+ withClinePassDeepSeekV4ToolReplayCompatibility(createOpenAIChatAdapter(provider)),
64
+ },
65
+ anthropic: {
66
+ wire: "anthropic",
67
+ mutation: "codex-owned",
68
+ create: (provider: OcxProviderConfig, context: AdapterFactoryContext) =>
69
+ createAnthropicAdapter(provider, context.cacheRetention),
70
+ },
71
+ "openai-responses": {
72
+ wire: "openai-responses",
73
+ mutation: "codex-owned",
74
+ create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) =>
75
+ createResponsesPassthroughAdapter(provider),
76
+ },
77
+ google: {
78
+ wire: "google",
79
+ mutation: "codex-owned",
80
+ create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) => createGoogleAdapter(provider),
81
+ },
82
+ kiro: {
83
+ wire: "kiro",
84
+ mutation: "codex-owned",
85
+ create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) => createKiroAdapter(provider),
86
+ },
87
+ azure: {
88
+ contractParent: "openai-responses",
89
+ create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) => createAzureAdapter(provider),
90
+ },
91
+ "azure-openai": {
92
+ contractParent: "openai-responses",
93
+ create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) => createAzureAdapter(provider),
94
+ },
95
+ cursor: {
96
+ wire: "cursor",
97
+ mutation: "codex-owned-with-gated-native-fallback",
98
+ create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) => createCursorAdapter(provider),
99
+ },
100
+ "mimo-free": {
101
+ contractParent: "openai-chat",
102
+ create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) => createMimoFreeAdapter(provider),
103
+ },
104
+ } as const satisfies Record<string, AdapterDefinition>;
105
+
106
+ export type AdapterId = keyof typeof ADAPTER_REGISTRY;
107
+ export type RegisteredAdapterDefinition = typeof ADAPTER_REGISTRY[AdapterId];
108
+
109
+ export function adapterDefinitions(): Array<[AdapterId, RegisteredAdapterDefinition]> {
110
+ return Object.entries(ADAPTER_REGISTRY) as Array<[AdapterId, RegisteredAdapterDefinition]>;
111
+ }
112
+
113
+ export function getAdapterDefinition(adapterId: unknown): RegisteredAdapterDefinition | undefined {
114
+ if (typeof adapterId !== "string" || !Object.hasOwn(ADAPTER_REGISTRY, adapterId)) return undefined;
115
+ return ADAPTER_REGISTRY[adapterId as AdapterId];
116
+ }
117
+
118
+ export function effectiveAdapterContract(adapterId: string): Readonly<{
119
+ wire: AdapterWire;
120
+ mutation: AdapterMutationContract;
121
+ }> {
122
+ const visited = new Set<string>();
123
+ let current = adapterId;
124
+
125
+ while (true) {
126
+ if (visited.has(current)) {
127
+ throw new Error(`Adapter contract cycle detected at ${current}`);
128
+ }
129
+ visited.add(current);
130
+
131
+ const definition = getAdapterDefinition(current);
132
+ if (!definition) throw new Error(`Unknown adapter: ${current}`);
133
+ if ("wire" in definition) {
134
+ return { wire: definition.wire, mutation: definition.mutation };
135
+ }
136
+ current = definition.contractParent;
137
+ }
138
+ }
139
+
140
+ export function createRegisteredAdapter(
141
+ provider: OcxProviderConfig,
142
+ context: AdapterFactoryContext = {},
143
+ ): ProviderAdapter {
144
+ const definition = getAdapterDefinition(provider.adapter);
145
+ if (!definition) throw new Error(`Unknown adapter: ${provider.adapter}`);
146
+ const adapter = definition.create(provider, context);
147
+ const buildRequest = adapter.buildRequest.bind(adapter);
148
+ adapter.buildRequest = (parsed, incoming) => {
149
+ const attachTierMetadata = (request: Awaited<ReturnType<ProviderAdapter["buildRequest"]>>) => {
150
+ // OpenAI-family adapters report the exact emitted field themselves. Other adapters
151
+ // still report an exact absence at this serialization boundary, which makes a routed
152
+ // Fast downgrade observable without asking core to infer an outbound body shape.
153
+ request.tierLog ??= createAdapterTierMetadata(
154
+ parsed.options.tierObservation,
155
+ parsed.options.tierDecision,
156
+ null,
157
+ null,
158
+ );
159
+ return request;
160
+ };
161
+ const request = buildRequest(parsed, incoming);
162
+ return request instanceof Promise
163
+ ? request.then(attachTierMetadata)
164
+ : attachTierMetadata(request);
165
+ };
166
+ if (adapter.runTurn && !adapter.tierLogForRunTurn) {
167
+ adapter.tierLogForRunTurn = parsed => createAdapterTierMetadata(
168
+ parsed.options.tierObservation,
169
+ parsed.options.tierDecision,
170
+ null,
171
+ null,
172
+ );
173
+ }
174
+ return adapter;
175
+ }
@@ -0,0 +1,67 @@
1
+ // Codex multi-agent v2 stamps a Responses-only `encrypted: true` marker on
2
+ // collaboration tool schemas (openai/codex 5f4d06ef; issue #85). It is an
3
+ // annotation for the ChatGPT backend only, so translated provider schemas must
4
+ // drop it without removing properties or definitions literally named `encrypted`.
5
+ const ENCRYPTED_MARKER_NAME_BAG_KEYS = new Set([
6
+ "properties",
7
+ "patternProperties",
8
+ "$defs",
9
+ "definitions",
10
+ "dependencies",
11
+ "dependentSchemas",
12
+ "dependentRequired",
13
+ ]);
14
+ const ENCRYPTED_MARKER_LITERAL_VALUE_KEYS = new Set(["const", "default", "enum", "examples"]);
15
+
16
+ /**
17
+ * The schema is caller-supplied, so its nesting depth is attacker-influenced. Native recursion
18
+ * would turn a deep schema into a stack overflow that takes down the request path, so this walks
19
+ * an explicit stack instead: depth costs heap, which is bounded and recoverable.
20
+ */
21
+ export function stripResponsesOnlyEncryptedMarker(node: unknown, inNameBag = false): unknown {
22
+ type Assign = (value: unknown) => void;
23
+ interface Frame { node: unknown; inNameBag: boolean; assign: Assign }
24
+
25
+ let result: unknown;
26
+ const stack: Frame[] = [{ node, inNameBag, assign: value => { result = value; } }];
27
+
28
+ while (stack.length > 0) {
29
+ const frame = stack.pop()!;
30
+ const current = frame.node;
31
+
32
+ if (Array.isArray(current)) {
33
+ const out: unknown[] = new Array(current.length);
34
+ frame.assign(out);
35
+ // Array items are schemas in their own right, never a name bag.
36
+ for (let i = current.length - 1; i >= 0; i--) {
37
+ stack.push({ node: current[i], inNameBag: false, assign: value => { out[i] = value; } });
38
+ }
39
+ continue;
40
+ }
41
+ if (!current || typeof current !== "object") {
42
+ frame.assign(current);
43
+ continue;
44
+ }
45
+
46
+ // A schema name may be `__proto__`; a null-prototype record keeps it as data.
47
+ const out: Record<string, unknown> = Object.create(null) as Record<string, unknown>;
48
+ frame.assign(out);
49
+
50
+ for (const [key, value] of Object.entries(current as Record<string, unknown>)) {
51
+ if (frame.inNameBag) {
52
+ // Inside a name bag every key is a caller-chosen name, so `encrypted` here is data.
53
+ stack.push({ node: value, inNameBag: false, assign: v => { out[key] = v; } });
54
+ } else if (key !== "encrypted") {
55
+ if (ENCRYPTED_MARKER_LITERAL_VALUE_KEYS.has(key)) {
56
+ // Literal payloads are values, not schemas: an `encrypted` key inside them is data.
57
+ out[key] = value;
58
+ } else {
59
+ const childInNameBag = ENCRYPTED_MARKER_NAME_BAG_KEYS.has(key);
60
+ stack.push({ node: value, inNameBag: childInNameBag, assign: v => { out[key] = v; } });
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ return result;
67
+ }
@@ -4,6 +4,13 @@ type QueueReader = (result: IteratorResult<AdapterEvent>) => void;
4
4
 
5
5
  export const PREFLIGHT_HEARTBEAT_RETAIN_LIMIT = 16;
6
6
 
7
+ /**
8
+ * Coalescing threshold for adjacent text/thinking deltas buffered with no
9
+ * waiting reader (UTF-16 code units). This is a merge-size ceiling, not a
10
+ * byte-memory cap: a single oversized incoming event stays one item.
11
+ */
12
+ export const COALESCE_MAX_CHUNK_LENGTH = 64 * 1024;
13
+
7
14
  export interface AdapterEventQueue {
8
15
  push(event: AdapterEvent): void;
9
16
  close(): void;
@@ -64,6 +71,33 @@ export function createAdapterEventQueue(opts?: {
64
71
  const maxBacklog = opts?.maxBacklog ?? 1_024;
65
72
  let closed = false;
66
73
 
74
+ // Merge an incoming delta into the buffered tail when no reader is waiting.
75
+ // The backlog cap counts events, not tokens, so a detached or briefly
76
+ // stalled consumer (e.g. a Codex app mid-reconnect whose disconnect Bun has
77
+ // not yet delivered) used to hit the cap within seconds of token-granular
78
+ // streaming and abort a healthy turn. Adjacent same-phase text deltas,
79
+ // adjacent thinking deltas, and consecutive heartbeats carry no ordering
80
+ // information between themselves, so merging them preserves every consumer
81
+ // contract while making the cap approximate buffered items again.
82
+ // Pushed objects may be retained by adapters, so the tail is REPLACED with
83
+ // a fresh object — never mutated (alias safety).
84
+ const coalesceIntoTail = (event: AdapterEvent): boolean => {
85
+ const tail = queued[queued.length - 1];
86
+ if (!tail) return false;
87
+ if (event.type === "heartbeat") return tail.type === "heartbeat";
88
+ if (event.type === "text_delta" && tail.type === "text_delta" && tail.phase === event.phase) {
89
+ if (tail.text.length + event.text.length > COALESCE_MAX_CHUNK_LENGTH) return false;
90
+ queued[queued.length - 1] = { type: "text_delta", text: tail.text + event.text, phase: tail.phase };
91
+ return true;
92
+ }
93
+ if (event.type === "thinking_delta" && tail.type === "thinking_delta") {
94
+ if (tail.thinking.length + event.thinking.length > COALESCE_MAX_CHUNK_LENGTH) return false;
95
+ queued[queued.length - 1] = { type: "thinking_delta", thinking: tail.thinking + event.thinking };
96
+ return true;
97
+ }
98
+ return false;
99
+ };
100
+
67
101
  const push = (event: AdapterEvent): void => {
68
102
  if (closed) return;
69
103
  const reader = readers.shift();
@@ -71,9 +105,10 @@ export function createAdapterEventQueue(opts?: {
71
105
  reader({ done: false, value: event });
72
106
  return;
73
107
  }
108
+ if (coalesceIntoTail(event)) return;
74
109
  if (queued.length >= maxBacklog) {
75
110
  opts?.onBacklogExceeded?.();
76
- queued.push({ type: "error", message: "consumer backlog exceeded — turn aborted" });
111
+ queued.push({ type: "error", message: "consumer stalled: adapter event backlog exceeded — turn aborted" });
77
112
  close();
78
113
  return;
79
114
  }
@@ -0,0 +1,119 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ /**
4
+ * Anthropic rejects a `tool_use.id` longer than this. Collision disambiguation has to fit
5
+ * inside it too, which is why candidates are assembled from parts instead of sliced at the end.
6
+ */
7
+ export const MAX_TOOL_CALL_ID_LENGTH = 64;
8
+
9
+ /** Hex characters of the deterministic tail. Fixed width: it is a discriminator, not a payload. */
10
+ const TOOL_CALL_ID_HASH_WIDTH = 8;
11
+
12
+ const CONFORMING_TOOL_CALL_ID = /^[a-zA-Z0-9_-]+$/;
13
+
14
+ /** An id Anthropic accepts as-is: right character set AND within the length bound. */
15
+ export function isConformingToolCallId(rawId: string): boolean {
16
+ return rawId.length > 0
17
+ && rawId.length <= MAX_TOOL_CALL_ID_LENGTH
18
+ && CONFORMING_TOOL_CALL_ID.test(rawId);
19
+ }
20
+
21
+ /**
22
+ * The parts a rewritten id is built from: the sanitized prefix and a deterministic tail
23
+ * derived from the raw id. Kept separate so collision handling can truncate the prefix
24
+ * without destroying the discriminator.
25
+ */
26
+ function toolCallIdComponents(rawId: string | undefined): { cleaned: string; hash: string } | undefined {
27
+ const raw = rawId ?? "";
28
+ if (raw.length === 0) return undefined;
29
+ const cleaned = raw.replace(/[^a-zA-Z0-9_-]/g, "_");
30
+ const hash = createHash("sha256").update(raw).digest("hex").slice(0, TOOL_CALL_ID_HASH_WIDTH);
31
+ return { cleaned, hash };
32
+ }
33
+
34
+ /** Assemble `prefix_hash`, truncating only the prefix, leaving `reserve` characters spare. */
35
+ function fitToolCallId(cleaned: string, hash: string, reserve = 0): string {
36
+ const tail = `_${hash}`;
37
+ const room = MAX_TOOL_CALL_ID_LENGTH - reserve - tail.length;
38
+ return cleaned.slice(0, Math.max(1, room)) + tail;
39
+ }
40
+
41
+ /**
42
+ * Normalize a tool call id into the character set and length Anthropic accepts.
43
+ *
44
+ * This is the stateless view, kept for callers that only need the shape of one id. It is NOT
45
+ * injective on its own: `anthropicToolCallId("call:a")` returns something like `call_a_1f2e3d4c`,
46
+ * and a raw id that already equals that value is returned unchanged — two distinct sources, one
47
+ * wire id. Anything building a whole request must use {@link createToolCallIdAllocator}, which
48
+ * reserves the conforming ids first and resolves collisions.
49
+ *
50
+ * Returns `undefined` for an empty id. Callers must handle that rather than falling back to the
51
+ * raw value: restoring `""` puts an id on the wire that Anthropic rejects (#1767).
52
+ */
53
+ export function anthropicToolCallId(rawId: string | undefined): string | undefined {
54
+ const raw = rawId ?? "";
55
+ if (raw.length === 0) return undefined;
56
+ if (isConformingToolCallId(raw)) return raw;
57
+ const parts = toolCallIdComponents(raw);
58
+ if (!parts) return undefined;
59
+ return fitToolCallId(parts.cleaned, parts.hash);
60
+ }
61
+
62
+ export type ToolCallIdAllocator = {
63
+ /** Claim an already-conforming source id so no rewrite can be handed the same value. */
64
+ reserve(rawId: string | undefined): void;
65
+ /** Wire id for a raw id, stable within the request. `undefined` means "not representable". */
66
+ allocate(rawId: string | undefined): string | undefined;
67
+ /** Wire id previously allocated for this raw id, without creating one. */
68
+ lookup(rawId: string | undefined): string | undefined;
69
+ };
70
+
71
+ /**
72
+ * Request-scoped raw-id to wire-id mapping.
73
+ *
74
+ * Two properties the stateless transform cannot provide:
75
+ *
76
+ * - **Injective.** Reserve every already-conforming id first, then allocate rewrites around them,
77
+ * appending a numeric suffix when a candidate is taken. Two distinct raw ids never share a wire id,
78
+ * including the case where one raw id already looks like another's normalized form, and including
79
+ * an ordinary 32-bit hash collision.
80
+ * - **Stable.** A tool result asks for the same raw id its call used and gets the same wire id, so
81
+ * call/result pairing survives normalization.
82
+ */
83
+ export function createToolCallIdAllocator(): ToolCallIdAllocator {
84
+ const rawToWire = new Map<string, string>();
85
+ const occupied = new Set<string>();
86
+
87
+ return {
88
+ reserve(rawId) {
89
+ if (!rawId || rawToWire.has(rawId)) return;
90
+ if (!isConformingToolCallId(rawId)) return;
91
+ rawToWire.set(rawId, rawId);
92
+ occupied.add(rawId);
93
+ },
94
+ allocate(rawId) {
95
+ if (!rawId) return undefined;
96
+ const existing = rawToWire.get(rawId);
97
+ if (existing) return existing;
98
+ if (isConformingToolCallId(rawId) && !occupied.has(rawId)) {
99
+ rawToWire.set(rawId, rawId);
100
+ occupied.add(rawId);
101
+ return rawId;
102
+ }
103
+ const parts = toolCallIdComponents(rawId);
104
+ if (!parts) return undefined;
105
+ let candidate = fitToolCallId(parts.cleaned, parts.hash);
106
+ for (let n = 2; occupied.has(candidate); n++) {
107
+ const suffix = `_${n}`;
108
+ candidate = fitToolCallId(parts.cleaned, parts.hash, suffix.length) + suffix;
109
+ }
110
+ rawToWire.set(rawId, candidate);
111
+ occupied.add(candidate);
112
+ return candidate;
113
+ },
114
+ lookup(rawId) {
115
+ if (!rawId) return undefined;
116
+ return rawToWire.get(rawId);
117
+ },
118
+ };
119
+ }
@@ -1,30 +1,63 @@
1
1
  import {
2
- isAllowedToolChoice,
3
2
  namespacedToolName,
4
- toolAllowedByChoice,
5
- toolChoiceAliases,
3
+ toolChoiceToolPredicate,
6
4
  type OcxRequestOptions,
7
5
  type OcxTool,
8
6
  type OcxProviderConfig,
9
7
  } from "../types";
8
+ import { CODE_MODE_RESULT_ECHO_SENTENCE } from "./exec-tool-result-normalize";
10
9
 
11
- const NEIGHBOR_AGENT_TOOL_NAMES = ["Read", "Grep", "Glob", "Bash", "LS", "apply_patch"] as const;
10
+ // Tool names that exist only in OTHER agent harnesses (Claude Code and friends). Naming one
11
+ // here tells a routed model not to call it unless this turn's catalog really lists it.
12
+ //
13
+ // `apply_patch` is deliberately absent: it is Codex's own first-class edit tool, not a
14
+ // neighbor's. Under Codex code mode it is reachable as a nested `tools.apply_patch(...)`
15
+ // helper declared inside the `exec` tool description rather than as a top-level wire tool,
16
+ // so a flat catalog check cannot see it and forbidding it pushed routed models into
17
+ // `python3` heredoc edits. The sibling list in `./cursor/tool-definitions.ts` never
18
+ // included it either.
19
+ const NEIGHBOR_AGENT_TOOL_NAMES = ["Read", "Grep", "Glob", "Bash", "LS"] as const;
20
+
21
+ /**
22
+ * The two halves of the code-mode shape, kept provider-neutral here.
23
+ *
24
+ * `./cursor/tool-definitions.ts` owns the Cursor-scoped versions of these
25
+ * (`isCursorCodeModeExecTool` / `isBareCodexShellBridgeTool`), but those additionally require
26
+ * the Cursor Responses namespace. This nudge is shared by Anthropic, Google, Kiro,
27
+ * OpenAI-chat and command-code, so it needs the same semantics without that provider gate.
28
+ */
29
+ const CODEX_UNIFIED_EXEC_TOOL_NAME = "exec";
30
+ const CODEX_SHELL_BRIDGE_TOOL_NAMES = ["exec_command", "shell_command"] as const;
31
+
32
+ export function isCodexCodeModeExecTool(tool: Pick<OcxTool, "namespace" | "name" | "freeform">): boolean {
33
+ return !tool.namespace && tool.name === CODEX_UNIFIED_EXEC_TOOL_NAME && tool.freeform === true;
34
+ }
35
+
36
+ /**
37
+ * BARE means un-namespaced, and the word is load-bearing.
38
+ *
39
+ * An MCP server can advertise its own `exec_command` or `shell_command` — a docker, k8s or ssh
40
+ * server plausibly does — and those arrive namespaced (`mcp__docker__exec_command`). They are
41
+ * not Codex's shell bridge, so they must not cancel code mode: a genuine code-mode turn that
42
+ * merely happens to sit beside an MCP shell tool would lose its guidance and fall back to the
43
+ * generic sentence.
44
+ *
45
+ * The Cursor original this was ported from (`isBareCodexShellBridgeTool`) carries the same
46
+ * `!tool.namespace` requirement; dropping it here made the name assert a check the body did not
47
+ * perform.
48
+ */
49
+ export function isBareShellBridgeTool(tool: Pick<OcxTool, "namespace" | "name">): boolean {
50
+ return !tool.namespace && (CODEX_SHELL_BRIDGE_TOOL_NAMES as readonly string[]).includes(tool.name);
51
+ }
12
52
 
13
53
  function quoteNames(names: readonly string[]): string {
14
- return names.map(name => `\`${name}\``).join(", ");
54
+ return names.map(name => "`" + name + "`").join(", ");
15
55
  }
16
56
 
17
57
  function uniqueNames(names: readonly string[]): string[] {
18
58
  return [...new Set(names.filter(name => name.trim().length > 0))];
19
59
  }
20
60
 
21
- function toolChoiceAllows(tool: Pick<OcxTool, "namespace" | "name">, toolChoice: OcxRequestOptions["toolChoice"] | undefined): boolean {
22
- if (!toolChoice || toolChoice === "auto" || toolChoice === "required") return true;
23
- if (toolChoice === "none") return false;
24
- if (isAllowedToolChoice(toolChoice)) return toolAllowedByChoice(tool, new Set(toolChoice.allowedTools));
25
- return toolChoiceAliases(tool).includes(toolChoice.name);
26
- }
27
-
28
61
  function isOpenAIOrChatGPTHost(hostname: string): boolean {
29
62
  return hostname === "openai.com"
30
63
  || hostname.endsWith(".openai.com")
@@ -40,19 +73,58 @@ export function shouldInjectNonOpenAIToolCatalogNudge(provider: Pick<OcxProvider
40
73
  }
41
74
  }
42
75
 
43
- export function buildNonOpenAIToolCatalogNudgeFromNames(wireNames: readonly string[] | undefined): string | undefined {
76
+ /**
77
+ * Codex code mode is a SEMANTIC property, not a name.
78
+ *
79
+ * The tool that carries it is a `freeform` `exec` whose body is JavaScript evaluated in a V8
80
+ * isolate, advertised alongside no bare shell bridge. A provider is free to advertise an
81
+ * ordinary structured tool called `exec` that runs a shell string — and a catalog can list
82
+ * `exec` next to `exec_command`/`shell_command`, which is the flat-bridge shape, not code mode.
83
+ *
84
+ * Classifying on the name alone would tell those turns that `exec` takes JavaScript and that
85
+ * shell is only reachable as a nested `tools.*` helper. Both are false there, and a model that
86
+ * believes them sends the wrong arguments or avoids a legitimate execution tool entirely.
87
+ *
88
+ * So callers that HAVE the tool objects decide with the semantic predicate and pass the verified
89
+ * wire name in; the name-only entry point cannot decide it and does not try.
90
+ */
91
+ function codeModeExecWireName(
92
+ advertised: ReadonlySet<string>,
93
+ verifiedName: string | undefined,
94
+ ): string | undefined {
95
+ if (!verifiedName) return undefined;
96
+ return advertised.has(verifiedName) ? verifiedName : undefined;
97
+ }
98
+
99
+ export function buildNonOpenAIToolCatalogNudgeFromNames(
100
+ wireNames: readonly string[] | undefined,
101
+ toWireName: (name: string) => string = name => name,
102
+ codeModeExecName?: string,
103
+ ): string | undefined {
44
104
  const names = uniqueNames(wireNames ?? []);
45
105
  if (names.length === 0) return undefined;
46
106
 
47
107
  const advertised = new Set(names);
48
- const unavailableNeighborNames = NEIGHBOR_AGENT_TOOL_NAMES.filter(name => !advertised.has(name));
108
+ // Compare in the catalog's own coordinate system. `advertised` holds WIRE names, so a
109
+ // provider that rewrites them (Claude OAuth `custom_`, Anthropic compat `cx_`) would never
110
+ // match a bare neighbor name and would forbid tools the turn actually advertises -- the
111
+ // catalog would list `custom_apply_patch` while the same sentence banned `apply_patch`.
112
+ const unavailableNeighborNames = NEIGHBOR_AGENT_TOOL_NAMES.filter(
113
+ name => !advertised.has(name) && !advertised.has(toWireName(name)),
114
+ );
115
+ const verifiedCodeModeExecName = codeModeExecWireName(advertised, codeModeExecName);
49
116
 
50
117
  return [
51
118
  "Tool contract: use the current tool catalog as ground truth.",
52
- `Valid tool names for this turn are exactly ${quoteNames(names)}.`,
119
+ "Valid tool names for this turn are exactly " + quoteNames(names) + ".",
120
+ "These listed names are the complete top-level tool-call surface for this turn.",
53
121
  "Call only listed names with their listed argument keys; do not invent, translate, or rename tools.",
122
+ "Names mentioned only in instructions, tool descriptions, argument descriptions, or nested helper APIs are not additional top-level tools.",
123
+ verifiedCodeModeExecName
124
+ ? "`" + verifiedCodeModeExecName + "` is Codex code mode: its body is JavaScript evaluated in a V8 isolate. Nested helpers are called INSIDE that body as `await tools.<name>(...)`, for example `await tools.exec_command({cmd: \"ls\"})` or `await tools.codex_app__list_threads({})`. Absence from the top-level catalog or from `" + verifiedCodeModeExecName + "`'s description is not absence: deferred helpers stay callable on `tools.<name>`. Discover them from the isolate global `ALL_TOOLS`, not `tools.ALL_TOOLS`. Do not skip an available nested helper because it is omitted from the listed top-level names. " + CODE_MODE_RESULT_ECHO_SENTENCE + " Nested `tools.apply_patch(input)` is host-executed: the string must begin exactly with `*** Begin Patch` and end with `*** End Patch` (no trailing `***` on those lines). OpenCodex does not rewrite JavaScript inside exec, so a decorated `*** Begin Patch ***` envelope is rejected by Codex before the file is touched."
125
+ : "If a listed tool exposes nested helpers such as a tools.* API, call the listed parent tool and use those helpers only inside that tool's input.",
54
126
  unavailableNeighborNames.length > 0
55
- ? `Do not use neighboring-agent tool names ${quoteNames(unavailableNeighborNames)} unless this turn's catalog lists those exact names.`
127
+ ? "Do not use neighboring-agent tool names " + quoteNames(unavailableNeighborNames) + " unless this turn's catalog lists those exact names."
56
128
  : undefined,
57
129
  "If you need shell, file search, file read, edit, or discovery behavior, choose the listed tool that provides that capability.",
58
130
  "Count a tool call only after its tool result returns; batch independent read-only calls when the runtime supports it.",
@@ -60,12 +132,24 @@ export function buildNonOpenAIToolCatalogNudgeFromNames(wireNames: readonly stri
60
132
  }
61
133
 
62
134
  export function buildNonOpenAIToolCatalogNudgeForTools(
63
- tools: readonly Pick<OcxTool, "namespace" | "name">[] | undefined,
135
+ tools: readonly Pick<OcxTool, "namespace" | "name" | "freeform">[] | undefined,
64
136
  toolChoice?: OcxRequestOptions["toolChoice"],
65
137
  toWireName: (tool: Pick<OcxTool, "namespace" | "name">) => string = tool => namespacedToolName(tool.namespace, tool.name),
66
138
  ): string | undefined {
67
- const visibleNames = tools
68
- ?.filter(tool => toolChoiceAllows(tool, toolChoice))
69
- .map(toWireName);
70
- return buildNonOpenAIToolCatalogNudgeFromNames(visibleNames);
139
+ const visible = tools?.filter(toolChoiceToolPredicate(toolChoice, tools));
140
+ const visibleNames = visible?.map(toWireName);
141
+ // Decide code mode from the tool OBJECTS, while the `freeform` flag still exists — reducing
142
+ // to wire names first throws away the only thing that distinguishes Codex's JavaScript
143
+ // `exec` from an ordinary structured tool that happens to share the name.
144
+ const codeModeExecTool = visible?.find(isCodexCodeModeExecTool);
145
+ const codeModeExecName = codeModeExecTool
146
+ && !visible?.some(isBareShellBridgeTool)
147
+ ? toWireName(codeModeExecTool)
148
+ : undefined;
149
+ // Neighbor names are bare and un-namespaced, so probe the same transform with a bare tool.
150
+ return buildNonOpenAIToolCatalogNudgeFromNames(
151
+ visibleNames,
152
+ name => toWireName({ name }),
153
+ codeModeExecName,
154
+ );
71
155
  }