@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
@@ -9,23 +9,43 @@ import type {
9
9
  OcxThinkingContent,
10
10
  OcxTool,
11
11
  OcxToolCall,
12
+ OcxReasoningReplayScopeRef,
12
13
  } from "../types";
13
- import { namespacedToolName } from "../types";
14
+ import { createToolChoiceResolver, namespacedToolName } from "../types";
14
15
  import { responsesRequestSchema } from "./schema";
15
- import { compactionItemToText } from "./compaction";
16
+ import { providerMetadataFromResponsesFunctionCall } from "./provider-opaque-metadata";
17
+ import { lookupReplayThoughtSignature } from "./thought-signature-replay";
18
+ import { compactionItemToText, isCompactionItemType } from "./compaction";
16
19
  import { previousResponseReplayPrefixLength } from "./state";
17
20
  import { decodeReasoningEnvelope } from "./reasoning-envelope";
18
21
  import { extractHostedWebSearch, WEB_SEARCH_TOOL_NAME } from "../web-search/synthetic-tool";
19
22
  import { extractHostedImageGeneration, IMAGE_GEN_TOOL_NAME } from "../images/synthetic-tool";
23
+ import { toolSearchDescription, toolSearchParameters } from "./tool-search-compat";
20
24
 
21
25
  function isObj(v: unknown): v is Record<string, unknown> {
22
26
  return typeof v === "object" && v !== null && !Array.isArray(v);
23
27
  }
24
28
 
29
+ /**
30
+ * Wrap a remembered proxy-side signature as provider metadata for a replayed tool call.
31
+ *
32
+ * The scope is REQUIRED for a hit. `parseRequest` runs before the route and account are
33
+ * chosen, so a caller that has not yet bound a replay scope gets nothing rather than a
34
+ * signature belonging to some other thread that happened to reuse the same `call_id`.
35
+ */
36
+ function replayThoughtSignatureMetadata(
37
+ callId: string,
38
+ scope: OcxReasoningReplayScopeRef | undefined,
39
+ ): { google: { thoughtSignature: string } } | undefined {
40
+ const signature = lookupReplayThoughtSignature(callId, scope);
41
+ return signature ? { google: { thoughtSignature: signature } } : undefined;
42
+ }
43
+
25
44
  type InputBlock =
26
45
  | { type: "input_text"; text: string }
27
46
  | { type: "text"; text: string }
28
47
  | { type: "input_image"; image_url?: string; file_id?: string; detail?: string }
48
+ | { type: "input_video"; video_url?: string }
29
49
  | { type: "input_file"; file_id?: string; filename?: string; file_data?: string };
30
50
 
31
51
  /** A usable reference string, or undefined. Empty strings and non-strings are not references. */
@@ -61,6 +81,9 @@ function inputContentParts(blocks: unknown): string | OcxContentPart[] {
61
81
  }
62
82
  // No usable reference: omit the block. A "[image: ?]" marker would claim an attachment
63
83
  // the request never carried, which is worse than dropping malformed input.
84
+ } else if (block.type === "input_video") {
85
+ const videoUrl = nonEmptyString(block.video_url);
86
+ if (videoUrl) parts.push({ type: "video", videoUrl });
64
87
  } else if (block.type === "input_file") {
65
88
  const b = block as { file_id?: string; filename?: string; file_data?: string };
66
89
  const fileId = nonEmptyString(b.file_id);
@@ -151,43 +174,53 @@ function buildTools(tools: unknown[] | undefined): OcxTool[] | undefined {
151
174
  if (namespace) tool.namespace = namespace;
152
175
  out.push(tool);
153
176
  };
177
+ const pushCustom = (t: Record<string, unknown>, namespace?: string) => {
178
+ // Freeform custom tools are lowered to a single string `input` because chat models cannot
179
+ // emit Responses grammar payloads directly. Keep tool-specific input guidance scoped to the
180
+ // tool that owns it: leaking apply_patch syntax into `exec` or another freeform tool teaches
181
+ // routed models that the nested helper name is itself a callable top-level tool.
182
+ const inputDescription = t.name === "apply_patch"
183
+ ? "Raw tool input. For apply_patch, begin exactly with `*** Begin Patch` (no trailing `***`), then use its standard patch envelope."
184
+ : "Raw freeform input for this tool.";
185
+ const tool: OcxTool = {
186
+ name: t.name as string,
187
+ description: (t.description as string) ?? "",
188
+ parameters: { type: "object", properties: { input: { type: "string", description: inputDescription } }, required: ["input"] },
189
+ freeform: true,
190
+ };
191
+ if (namespace) tool.namespace = namespace;
192
+ out.push(tool);
193
+ };
154
194
  for (const t of tools) {
155
195
  if (!isObj(t)) continue;
196
+ if (t.type === "function" && isObj(t.function) && typeof t.function.name === "string" && t.function.name.length > 0) {
197
+ pushFn(t.function as Record<string, unknown>);
198
+ continue;
199
+ }
156
200
  if (t.type === "function" && typeof t.name === "string") {
157
201
  pushFn(t);
158
202
  } else if (t.type === "namespace" && Array.isArray(t.tools)) {
159
- // MCP tools arrive grouped under a namespace tool; flatten the inner function tools so
160
- // chat-completions models receive them (round-trip restores the namespace in the bridge).
161
- const ns = typeof t.name === "string" ? t.name : undefined;
203
+ // Codex 0.147 groups its ordinary client tools under the reserved `functions` namespace,
204
+ // including freeform custom tools such as code-mode `exec`. Those children are still
205
+ // top-level Responses tools, so flatten them without a namespace. Other namespace groups
206
+ // are MCP-style and keep their namespace for round-trip routing.
207
+ const builtinFunctions = t.name === "functions";
208
+ const ns = typeof t.name === "string" && !builtinFunctions ? t.name : undefined;
162
209
  for (const inner of t.tools as unknown[]) {
163
210
  if (isObj(inner) && inner.type === "function" && typeof inner.name === "string") pushFn(inner, ns);
211
+ else if (isObj(inner) && inner.type === "custom" && typeof inner.name === "string") pushCustom(inner, ns);
164
212
  }
165
213
  }
166
214
  else if (t.type === "custom" && typeof t.name === "string") {
167
- // Freeform custom tool (e.g. apply_patch). Chat models can't emit a lark grammar, so expose a
168
- // function with a single string `input` carrying the raw tool body; the bridge relays the model's
169
- // call back as a custom_tool_call (Codex's freeform handler rejects a function_call → fatal abort).
170
- out.push({
171
- name: t.name,
172
- description: (t.description as string) ?? "",
173
- parameters: { type: "object", properties: { input: { type: "string", description: "Raw tool input. For apply_patch, begin exactly with `*** Begin Patch` (no trailing `***`), then use its standard patch envelope." } }, required: ["input"] },
174
- freeform: true,
175
- });
215
+ pushCustom(t);
176
216
  }
177
217
  else if (t.type === "tool_search") {
178
218
  // Client-executed tool discovery — the gateway to deferred tools (subagents, extra MCP tools).
179
219
  // Expose as a function so chat models can call it; the bridge relays it as a tool_search_call.
180
220
  out.push({
181
221
  name: "tool_search",
182
- description: (t.description as string) ?? "Search for additional tools to load for the next turn.",
183
- parameters: (isObj(t.parameters) ? t.parameters : {
184
- type: "object",
185
- properties: {
186
- query: { type: "string", description: "Search query for tools to load." },
187
- limit: { type: "number", description: "Maximum number of tools to return." },
188
- },
189
- required: ["query"],
190
- }) as Record<string, unknown>,
222
+ description: toolSearchDescription(t),
223
+ parameters: normalizeParameters(toolSearchParameters(t)),
191
224
  toolSearch: true,
192
225
  });
193
226
  }
@@ -263,9 +296,70 @@ function findToolById(messages: OcxMessage[], callId: string): { name: string; n
263
296
  return { name: "" };
264
297
  }
265
298
 
299
+ /**
300
+ * Attach pending reasoning to the assistant turn that owns the given call id.
301
+ * Reconstructed histories (resume/retry/synthetic) can order a `reasoning`
302
+ * item AFTER the `function_call` it belongs to; without this, the pending
303
+ * buffer is cleared at the tool output and the turn serializes without
304
+ * `reasoning_content`, which DeepSeek thinking mode rejects with HTTP 400
305
+ * (issue #950).
306
+ */
307
+ function attachPendingReasoningToCallOwner(
308
+ messages: OcxMessage[],
309
+ callId: string,
310
+ pendingReasoning: Array<{ part: OcxThinkingContent; envelopeSigned: boolean }>,
311
+ ): void {
312
+ if (pendingReasoning.length === 0 || !callId) return;
313
+ for (let i = messages.length - 1; i >= 0; i--) {
314
+ const m = messages[i];
315
+ if (m.role !== "assistant") continue;
316
+ for (const part of m.content) {
317
+ if (part.type === "toolCall" && part.id === callId) {
318
+ // Prepend so thinking still precedes tool_use for adapters that require
319
+ // that ordering (Anthropic-style replay).
320
+ m.content = [...pendingReasoning.map(entry => entry.part), ...m.content];
321
+ return;
322
+ }
323
+ }
324
+ }
325
+ }
326
+
266
327
  const REASONING_EFFORTS = new Set(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
267
328
 
268
- export function parseRequest(body: unknown): OcxParsedRequest {
329
+ /**
330
+ * Namespace a custom tool was declared under, by its bare name.
331
+ *
332
+ * A `custom_tool_call` echoed back by the client carries only the bare name — the bridge
333
+ * emits `{"type":"custom_tool_call","name":"exec"}` even when the tool was declared as
334
+ * `mcp__functions__exec`. Without this lookup the namespace is lost on the return trip,
335
+ * and the adapters replay history through `namespacedToolName(namespace, name)`, which
336
+ * then produces a bare `exec` the provider may not have. Ordinary `function_call` items
337
+ * do not need this: they carry `namespace` on the wire.
338
+ */
339
+ function customToolNamespaces(tools: unknown): Map<string, string> {
340
+ const out = new Map<string, string>();
341
+ if (!Array.isArray(tools)) return out;
342
+ for (const spec of tools) {
343
+ if (!isObj(spec) || spec.type !== "namespace" || !Array.isArray(spec.tools)) continue;
344
+ const namespace = typeof spec.name === "string" ? spec.name : undefined;
345
+ // Codex 0.147 groups ordinary client tools under the reserved `functions` namespace and
346
+ // buildTools deliberately flattens those without a namespace. Mirror that here, or the
347
+ // reconstruction would invent a namespace the request never advertised.
348
+ if (!namespace || namespace === "functions") continue;
349
+ for (const inner of spec.tools) {
350
+ if (!isObj(inner) || inner.type !== "custom" || typeof inner.name !== "string") continue;
351
+ // Ambiguous bare names are already rejected upstream, so first declaration wins.
352
+ if (!out.has(inner.name)) out.set(inner.name, namespace);
353
+ }
354
+ }
355
+ return out;
356
+ }
357
+
358
+ export function parseRequest(
359
+ body: unknown,
360
+ parseOptions?: { replayCacheScope?: OcxReasoningReplayScopeRef },
361
+ ): OcxParsedRequest {
362
+ const replayCacheScope = parseOptions?.replayCacheScope;
269
363
  const replayedInputPrefixLength = previousResponseReplayPrefixLength(body);
270
364
  const parsed = responsesRequestSchema.safeParse(body);
271
365
  if (!parsed.success) {
@@ -274,6 +368,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
274
368
  const data = parsed.data;
275
369
  const now = Date.now();
276
370
  const messages: OcxMessage[] = [];
371
+ // Built before the item loop: a custom_tool_call echoed back in `input` needs the
372
+ // namespace from the request's own tool catalog to survive the round trip.
373
+ const customToolNamespacesByName = customToolNamespaces(data.tools);
277
374
  const systemPrompt: string[] = [];
278
375
  // Responses reasoning siblings belong to the following assistant, including across call items.
279
376
  // Keep them off the message list until that assistant arrives; turn boundaries clear the array.
@@ -296,17 +393,33 @@ export function parseRequest(body: unknown): OcxParsedRequest {
296
393
  // synthetic `{type:"compaction"}` output item (src/responses/compaction.ts). Flagged for the server.
297
394
  let compactionRequest = false;
298
395
  let contextCompactionBoundary = false;
396
+ let continuationConversationMessageIndex: number | undefined;
299
397
 
300
398
  if (typeof data.instructions === "string" && data.instructions.length > 0) {
301
399
  systemPrompt.push(data.instructions);
302
400
  }
303
401
 
304
402
  if (typeof data.input === "string") {
403
+ if (data.previous_response_id) continuationConversationMessageIndex = messages.length;
305
404
  messages.push({ role: "user", content: data.input, timestamp: now });
306
405
  } else if (data.input) {
307
406
  for (let inputIndex = 0; inputIndex < data.input.length; inputIndex++) {
308
407
  const item = data.input[inputIndex];
309
408
  const effectiveType = (item as { type?: string }).type ?? ("role" in item ? "message" : undefined);
409
+ const itemRole = (item as { role?: string }).role;
410
+ // Raw protocol items do not map one-to-one onto context messages. Capture the boundary while
411
+ // both representations are available so later metadata can stay before conversation in both.
412
+ if (
413
+ data.previous_response_id
414
+ && inputIndex >= replayedInputPrefixLength
415
+ && continuationConversationMessageIndex === undefined
416
+ && (
417
+ effectiveType === "agent_message"
418
+ || (effectiveType === "message" && (itemRole === "user" || itemRole === "assistant"))
419
+ )
420
+ ) {
421
+ continuationConversationMessageIndex = messages.length;
422
+ }
310
423
 
311
424
  if (effectiveType === "compaction_trigger") {
312
425
  compactionRequest = true;
@@ -325,7 +438,7 @@ export function parseRequest(body: unknown): OcxParsedRequest {
325
438
  continue;
326
439
  }
327
440
 
328
- if (effectiveType === "compaction" || effectiveType === "compaction_summary" || effectiveType === "context_compaction") {
441
+ if (isCompactionItemType(effectiveType)) {
329
442
  // A stored summary from a previous compaction. Decode our ocx1 envelope into plain text so
330
443
  // the routed model keeps the compacted context; real OpenAI-encrypted blobs degrade to a note.
331
444
  // `context_compaction` (encrypted_content optional) is codex-rs's local-compaction marker;
@@ -416,6 +529,18 @@ export function parseRequest(body: unknown): OcxParsedRequest {
416
529
  : null;
417
530
  const thinkingText = envelope?.txt || text;
418
531
 
532
+ // Kiro reasoning round-trip: a krc-only item carries nothing renderable — it is provider
533
+ // state for the assistant turn that ALREADY closed, because Kiro emits its
534
+ // reasoningContentEvent at the END of a turn (after content AND tool calls, verified
535
+ // against kiro-cli 2.14.1/2.16.0). Folding it into the FOLLOWING turn like ordinary
536
+ // reasoning would attach turn N's blob to turn N+1, so attach it backwards instead. With
537
+ // no assistant turn to own it the blob is dropped rather than mis-paired.
538
+ if (envelope?.krc && thinkingText.length === 0) {
539
+ const previous = messages[messages.length - 1];
540
+ if (previous?.role === "assistant") previous.kiroRedactedReasoning = envelope.krc;
541
+ continue;
542
+ }
543
+
419
544
  // Native/non-ocxr1 encrypted-only reasoning is opaque here. Do not create a detached
420
545
  // assistant turn or invent replayable plaintext/signatures from the encrypted payload.
421
546
  if (thinkingText.length > 0) {
@@ -442,7 +567,7 @@ export function parseRequest(body: unknown): OcxParsedRequest {
442
567
  }
443
568
 
444
569
  if (effectiveType === "function_call") {
445
- const call = item as { id?: string; call_id: string; name: string; arguments?: string; namespace?: string };
570
+ const call = item as { id?: string; call_id: string; name: string; arguments?: string; namespace?: string; extra_content?: unknown };
446
571
  // Tolerate empty/non-JSON arguments (e.g. a no-arg tool call serialized as "") instead of
447
572
  // throwing — a single poisoned history item would otherwise 400 every subsequent turn.
448
573
  let args: Record<string, unknown> = {};
@@ -463,16 +588,32 @@ export function parseRequest(body: unknown): OcxParsedRequest {
463
588
  type: "toolCall", id: call.call_id, name: call.name, arguments: args,
464
589
  ...(call.namespace ? { namespace: call.namespace } : {}),
465
590
  };
591
+ // Provider-opaque metadata (e.g. a Gemini thought signature) travels with the call so a
592
+ // history-replayed or previous_response_id turn rebuilds the same signed part instead of
593
+ // depending on the same-process replay cache (issue #1735). Real clients do not echo
594
+ // extra_content on replay, so fall back to the proxy-side store keyed by call_id.
595
+ const providerMetadata = providerMetadataFromResponsesFunctionCall(call)
596
+ ?? (typeof call.call_id === "string"
597
+ ? replayThoughtSignatureMetadata(call.call_id, replayCacheScope)
598
+ : undefined);
599
+ if (providerMetadata) toolCall.providerMetadata = providerMetadata;
466
600
  assistantHolderWithReasoning().content.push(toolCall);
467
601
  continue;
468
602
  }
469
603
 
470
604
  if (effectiveType === "custom_tool_call") {
471
605
  const call = item as { id?: string; call_id: string; name: string; input: string };
606
+ const remembered = typeof call.call_id === "string" ? replayThoughtSignatureMetadata(call.call_id, replayCacheScope) : undefined;
607
+ // Reconstruct the namespace the request declared this tool under. The wire item
608
+ // carries only the bare name, so without this the round trip loses it and adapters
609
+ // replay the call as an unnamespaced tool the provider may not expose.
610
+ const customNamespace = customToolNamespacesByName.get(call.name);
472
611
  const toolCall: OcxToolCall = {
473
612
  type: "toolCall", id: call.call_id, name: call.name,
474
613
  arguments: { input: call.input ?? "" },
475
614
  customWireName: call.name,
615
+ ...(customNamespace ? { namespace: customNamespace } : {}),
616
+ ...(remembered ? { providerMetadata: remembered } : {}),
476
617
  };
477
618
  assistantHolderWithReasoning().content.push(toolCall);
478
619
  continue;
@@ -485,9 +626,11 @@ export function parseRequest(body: unknown): OcxParsedRequest {
485
626
  const callId = call.call_id ?? call.id;
486
627
  if (callId) {
487
628
  const command = Array.isArray(call.action?.command) ? call.action.command : [];
629
+ const remembered = replayThoughtSignatureMetadata(callId, replayCacheScope);
488
630
  assistantHolderWithReasoning().content.push({
489
631
  type: "toolCall", id: callId, name: "shell",
490
632
  arguments: command.length > 0 ? { command } : {},
633
+ ...(remembered ? { providerMetadata: remembered } : {}),
491
634
  });
492
635
  }
493
636
  continue;
@@ -506,9 +649,11 @@ export function parseRequest(body: unknown): OcxParsedRequest {
506
649
  // history stays complete (otherwise the model re-issues tool_search forever).
507
650
  const call = item as { id?: string; call_id?: string; arguments?: unknown };
508
651
  const callId = call.call_id ?? call.id ?? "";
652
+ const remembered = callId ? replayThoughtSignatureMetadata(callId, replayCacheScope) : undefined;
509
653
  assistantHolderWithReasoning().content.push({
510
654
  type: "toolCall", id: callId, name: "tool_search",
511
655
  arguments: isObj(call.arguments) ? call.arguments : {},
656
+ ...(remembered ? { providerMetadata: remembered } : {}),
512
657
  });
513
658
  continue;
514
659
  }
@@ -545,8 +690,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
545
690
  }
546
691
 
547
692
  if (effectiveType === "function_call_output") {
548
- pendingReasoning.length = 0;
549
693
  const output = item as { call_id: string; output?: string | unknown[] };
694
+ attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
695
+ pendingReasoning.length = 0;
550
696
  const toolInfo = findToolById(messages, output.call_id);
551
697
  messages.push({
552
698
  role: "toolResult", toolCallId: output.call_id,
@@ -558,8 +704,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
558
704
  }
559
705
 
560
706
  if (effectiveType === "custom_tool_call_output") {
561
- pendingReasoning.length = 0;
562
707
  const output = item as { call_id: string; output: string | unknown[] };
708
+ attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
709
+ pendingReasoning.length = 0;
563
710
  const toolInfo = findToolById(messages, output.call_id);
564
711
  messages.push({
565
712
  role: "toolResult", toolCallId: output.call_id,
@@ -572,10 +719,22 @@ export function parseRequest(body: unknown): OcxParsedRequest {
572
719
  }
573
720
  }
574
721
  }
722
+ if (data.previous_response_id && continuationConversationMessageIndex === undefined) {
723
+ continuationConversationMessageIndex = messages.length;
724
+ }
575
725
 
576
726
  const declaredTools = buildTools(data.tools as unknown[] | undefined) ?? [];
577
727
  const loadedTools = buildTools(loadedToolSpecs) ?? [];
578
728
  const loadedToolNames = new Set(loadedTools.map(t => namespacedToolName(t.namespace, t.name)));
729
+ const wireOwners = new Map<string, OcxTool>();
730
+ for (const tool of [...declaredTools, ...loadedTools]) {
731
+ const wireName = namespacedToolName(tool.namespace, tool.name);
732
+ const previous = wireOwners.get(wireName);
733
+ if (previous && (previous.namespace !== tool.namespace || previous.name !== tool.name || previous.freeform !== tool.freeform || previous.toolSearch !== tool.toolSearch)) {
734
+ throw new Error(`ambiguous tool catalog: multiple logical tools map to wire name ${wireName}`);
735
+ }
736
+ wireOwners.set(wireName, tool);
737
+ }
579
738
  const seenTools = new Set<string>();
580
739
  const mergedTools = [...declaredTools, ...loadedTools]
581
740
  .filter(t => {
@@ -601,6 +760,15 @@ export function parseRequest(body: unknown): OcxParsedRequest {
601
760
  options.stopSequences = typeof data.stop === "string" ? [data.stop] : data.stop;
602
761
  }
603
762
  const tc = mapToolChoice(data.tool_choice);
763
+ if (tc && typeof tc === "object") {
764
+ const selectors = "allowedTools" in tc ? tc.allowedTools : [tc.name];
765
+ const resolver = createToolChoiceResolver(mergedTools);
766
+ for (const selector of selectors) {
767
+ if (resolver.candidateCount(selector) > 1) {
768
+ throw new Error(`ambiguous tool_choice name: ${selector}`);
769
+ }
770
+ }
771
+ }
604
772
  if (tc !== undefined) options.toolChoice = tc;
605
773
  if (data.parallel_tool_calls !== undefined) options.parallelToolCalls = data.parallel_tool_calls;
606
774
  // Upstream codex-rs converts "ultra" to "max" at the inference boundary (core/src/client.rs
@@ -626,9 +794,12 @@ export function parseRequest(body: unknown): OcxParsedRequest {
626
794
  ...(data.tools as unknown[] ?? []),
627
795
  ...loadedToolSpecs,
628
796
  ]);
629
- // Detect structured-output mode (Responses `text.format`) so the web-search sidecar can render its
630
- // tool_result as JSON rather than prose that could corrupt the model's schema-constrained answer.
631
- const structuredOutput = detectStructuredOutput(data.text);
797
+ // Capture structured-output mode (Responses `text.format`): the format object rides
798
+ // options.textFormat for adapters whose wire has an equivalent (openai-chat response_format),
799
+ // while the `_structuredOutput` flag keeps the web-search sidecar rendering its tool_result
800
+ // as JSON rather than prose that could corrupt the model's schema-constrained answer.
801
+ const textFormat = parseTextFormat(data.text);
802
+ if (textFormat) options.textFormat = textFormat;
632
803
 
633
804
  return {
634
805
  modelId: data.model,
@@ -638,19 +809,35 @@ export function parseRequest(body: unknown): OcxParsedRequest {
638
809
  options,
639
810
  _rawBody: body,
640
811
  ...(replayedInputPrefixLength > 0 ? { _replayPrefixLen: replayedInputPrefixLength } : {}),
812
+ ...(continuationConversationMessageIndex !== undefined
813
+ ? { _continuationConversationMessageIndex: continuationConversationMessageIndex }
814
+ : {}),
641
815
  ...(webSearch ? { _webSearch: webSearch } : {}),
642
816
  ...(imageGen ? { _imageGeneration: imageGen } : {}),
643
- ...(structuredOutput ? { _structuredOutput: true } : {}),
817
+ ...(textFormat ? { _structuredOutput: true } : {}),
644
818
  ...(compactionRequest ? { _compactionRequest: true } : {}),
645
819
  ...(contextCompactionBoundary ? { _contextCompactionBoundary: true } : {}),
646
820
  };
647
821
  }
648
822
 
649
- /** True when the Responses `text.format` requests structured output (json_schema or json_object). */
650
- function detectStructuredOutput(text: unknown): boolean {
651
- if (!isObj(text)) return false;
823
+ /**
824
+ * The Responses `text.format` object when it requests structured output (json_schema or
825
+ * json_object), undefined otherwise. Acceptance is identical to the boolean detector this
826
+ * replaces; unknown or malformed formats are ignored, never rejected, so the native
827
+ * passthrough keeps forwarding whatever the caller sent via `_rawBody`.
828
+ */
829
+ function parseTextFormat(text: unknown): OcxRequestOptions["textFormat"] {
830
+ if (!isObj(text)) return undefined;
652
831
  const format = (text as { format?: unknown }).format;
653
- if (!isObj(format)) return false;
654
- const t = (format as { type?: unknown }).type;
655
- return t === "json_schema" || t === "json_object";
832
+ if (!isObj(format)) return undefined;
833
+ const f = format as { type?: unknown; name?: unknown; description?: unknown; schema?: unknown; strict?: unknown };
834
+ if (f.type === "json_object") return { type: "json_object" };
835
+ if (f.type !== "json_schema") return undefined;
836
+ return {
837
+ type: "json_schema",
838
+ ...(typeof f.name === "string" ? { name: f.name } : {}),
839
+ ...(typeof f.description === "string" ? { description: f.description } : {}),
840
+ ...(isObj(f.schema) ? { schema: f.schema as Record<string, unknown> } : {}),
841
+ ...(typeof f.strict === "boolean" ? { strict: f.strict } : {}),
842
+ };
656
843
  }
@@ -0,0 +1,98 @@
1
+ import type {
2
+ OcxProviderContinuationOwner,
3
+ OcxReasoningReplayIdentity,
4
+ } from "../types";
5
+
6
+ const bounded = (value: unknown, max: number): value is string =>
7
+ typeof value === "string" && value.length > 0 && value.length <= max;
8
+
9
+ const isPlainRecord = (value: unknown): value is Record<string, unknown> => {
10
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
11
+ const prototype = Object.getPrototypeOf(value);
12
+ return prototype === Object.prototype || prototype === null;
13
+ };
14
+
15
+ const defineOwn = (target: Record<string, unknown>, key: string, value: unknown): void => {
16
+ Object.defineProperty(target, key, {
17
+ value,
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ });
22
+ };
23
+
24
+ /** Recursively merge provider-owned plain objects; arrays and scalar values replace prior state. */
25
+ export function mergeProviderContinuationPayload(
26
+ inherited: Readonly<Record<string, unknown>>,
27
+ emitted: Readonly<Record<string, unknown>>,
28
+ ): Record<string, unknown> {
29
+ const merged: Record<string, unknown> = {};
30
+ for (const [key, value] of Object.entries(inherited)) defineOwn(merged, key, value);
31
+ for (const [key, value] of Object.entries(emitted)) {
32
+ const prior = Object.hasOwn(merged, key) ? merged[key] : undefined;
33
+ defineOwn(
34
+ merged,
35
+ key,
36
+ isPlainRecord(prior) && isPlainRecord(value)
37
+ ? mergeProviderContinuationPayload(prior, value)
38
+ : value,
39
+ );
40
+ }
41
+ return merged;
42
+ }
43
+
44
+ /** Validate proxy-authored continuation ownership before trusting persisted state. */
45
+ export function isValidProviderContinuationOwner(
46
+ value: unknown,
47
+ ): value is OcxProviderContinuationOwner {
48
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
49
+ const owner = value as Record<string, unknown>;
50
+ return owner.version === 1
51
+ && bounded(owner.providerName, 256)
52
+ && typeof owner.providerDestinationIdentity === "string"
53
+ && /^destination:[0-9a-f]{64}$/.test(owner.providerDestinationIdentity)
54
+ && bounded(owner.adapterName, 128)
55
+ && bounded(owner.modelId, 512)
56
+ && typeof owner.credentialIdentity === "string"
57
+ && /^(key|oauth|codex):[0-9a-f]{64}$/.test(owner.credentialIdentity);
58
+ }
59
+
60
+ /** Reuse the exact process-local route identity already established for reasoning replay. */
61
+ export function providerContinuationOwnerFromReplayIdentity(
62
+ identity: Readonly<OcxReasoningReplayIdentity> | undefined,
63
+ ): OcxProviderContinuationOwner | undefined {
64
+ if (!identity) return undefined;
65
+ const owner: OcxProviderContinuationOwner = {
66
+ version: 1,
67
+ providerName: identity.providerName,
68
+ providerDestinationIdentity: identity.providerDestinationIdentity,
69
+ adapterName: identity.adapterName,
70
+ modelId: identity.modelId,
71
+ credentialIdentity: identity.credentialIdentity,
72
+ };
73
+ return isValidProviderContinuationOwner(owner) ? owner : undefined;
74
+ }
75
+
76
+ export function sameProviderContinuationOwner(
77
+ left: OcxProviderContinuationOwner,
78
+ right: OcxProviderContinuationOwner,
79
+ ): boolean {
80
+ return left.version === right.version
81
+ && left.providerName === right.providerName
82
+ && left.providerDestinationIdentity === right.providerDestinationIdentity
83
+ && left.adapterName === right.adapterName
84
+ && left.modelId === right.modelId
85
+ && left.credentialIdentity === right.credentialIdentity;
86
+ }
87
+
88
+ /** Cursor hashes this non-secret namespace with the client thread id. */
89
+ export function providerContinuationRouteScope(owner: OcxProviderContinuationOwner): string {
90
+ return JSON.stringify([
91
+ "provider-continuation-v1",
92
+ owner.providerName,
93
+ owner.providerDestinationIdentity,
94
+ owner.adapterName,
95
+ owner.modelId,
96
+ owner.credentialIdentity,
97
+ ]);
98
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Provider-opaque tool-call metadata across the Responses boundary (issue #1735).
3
+ *
4
+ * Gemini issues a `thoughtSignature` on the exact part that carries a function call, and the
5
+ * next request is only valid if that signature comes back on the part rebuilt from that same
6
+ * call. Every synthetic loop in this proxy (web search, images, continuation replay) tears a
7
+ * tool call down into id/name/arguments and builds a fresh one, which silently dropped the
8
+ * signature and left only the same-process replay cache to paper over it. History replay and
9
+ * `previous_response_id` had no cache to fall back on.
10
+ *
11
+ * This module is the single seam where that metadata crosses into and out of the Responses
12
+ * wire, so a loop that rebuilds a call only has to carry one field instead of knowing about
13
+ * any provider. Values are treated as opaque: never parsed, merged, re-encoded, or synthesized.
14
+ */
15
+ import type { OcxProviderOpaqueToolCallMetadata } from "../types";
16
+
17
+ /** Wire shape: `extra_content.google.thought_signature` on a Responses function_call item. */
18
+ interface ResponsesExtraContent {
19
+ google?: { thought_signature?: unknown };
20
+ }
21
+
22
+ function isObj(value: unknown): value is Record<string, unknown> {
23
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24
+ }
25
+
26
+ /**
27
+ * Same ceiling the Antigravity replay cache already enforces on a stored signature. An opaque
28
+ * token this large is not a real signature, and accepting it would let a caller push unbounded
29
+ * state through history replay.
30
+ */
31
+ const MAX_SIGNATURE_BYTES = 64 * 1024;
32
+
33
+ export function isCarryableSignature(value: unknown): value is string {
34
+ if (typeof value !== "string" || value.length === 0) return false;
35
+ // Cheap length pre-check: UTF-8 is at most 3 bytes per UTF-16 code unit for the BMP, so this
36
+ // skips the encode for the overwhelmingly common short case.
37
+ if (value.length <= MAX_SIGNATURE_BYTES / 3) return true;
38
+ return Buffer.byteLength(value, "utf8") <= MAX_SIGNATURE_BYTES;
39
+ }
40
+
41
+ /** Read provider metadata off an inbound Responses function_call item. */
42
+ export function providerMetadataFromResponsesFunctionCall(
43
+ item: { extra_content?: unknown } | undefined,
44
+ ): OcxProviderOpaqueToolCallMetadata | undefined {
45
+ const extra = item?.extra_content;
46
+ if (!isObj(extra)) return undefined;
47
+ const google = (extra as ResponsesExtraContent).google;
48
+ if (!isObj(google)) return undefined;
49
+ const signature = google.thought_signature;
50
+ if (!isCarryableSignature(signature)) return undefined;
51
+ return { google: { thoughtSignature: signature } };
52
+ }
53
+
54
+ /** Serialize provider metadata onto an outbound Responses function_call item. */
55
+ export function responsesExtraContentFromProviderMetadata(
56
+ metadata: OcxProviderOpaqueToolCallMetadata | undefined,
57
+ ): { extra_content: { google: { thought_signature: string } } } | undefined {
58
+ const signature = metadata?.google?.thoughtSignature;
59
+ if (!isCarryableSignature(signature)) return undefined;
60
+ return { extra_content: { google: { thought_signature: signature } } };
61
+ }
62
+
63
+ /**
64
+ * Copy metadata for a rebuilt tool call. A signature belongs to one specific part, so a loop
65
+ * that fans one model response into several calls must copy per call and never share or merge.
66
+ */
67
+ export function cloneProviderOpaqueToolCallMetadata(
68
+ metadata: OcxProviderOpaqueToolCallMetadata | undefined,
69
+ ): OcxProviderOpaqueToolCallMetadata | undefined {
70
+ const signature = metadata?.google?.thoughtSignature;
71
+ if (!isCarryableSignature(signature)) return undefined;
72
+ return { google: { thoughtSignature: signature } };
73
+ }
@@ -24,6 +24,12 @@ export interface ReasoningEnvelope {
24
24
  * so replay needs it even though the visible summary was suppressed.
25
25
  */
26
26
  txt?: string;
27
+ /**
28
+ * Kiro `reasoningContentEvent.redactedContent`: a KMS-encrypted reasoning blob that is opaque to
29
+ * the proxy. Kiro's own CLI replays it on the matching `assistantResponseMessage` to preserve
30
+ * model reasoning across turns, so it round-trips here the same way a signature does.
31
+ */
32
+ krc?: string;
27
33
  }
28
34
 
29
35
  export function encodeReasoningEnvelope(envelope: ReasoningEnvelope): string {
@@ -45,7 +51,9 @@ export function decodeReasoningEnvelope(encryptedContent: string): ReasoningEnve
45
51
  }
46
52
  const txt = (parsed as { txt?: unknown }).txt;
47
53
  if (typeof txt === "string" && txt.length > 0) envelope.txt = txt;
48
- return envelope.sig || envelope.red || envelope.txt ? envelope : null;
54
+ const krc = (parsed as { krc?: unknown }).krc;
55
+ if (typeof krc === "string" && krc.length > 0) envelope.krc = krc;
56
+ return envelope.sig || envelope.red || envelope.txt || envelope.krc ? envelope : null;
49
57
  } catch {
50
58
  return null;
51
59
  }