@iislee/opencodex 2.11.0 → 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (675) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +114 -19
  3. package/bin/ocx.mjs +164 -36
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-BF38heuV.js +104 -0
  6. package/gui/dist/assets/index-DMiI18Kv.css +1 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +19 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +376 -52
  44. package/src/adapters/base.ts +54 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +601 -0
  48. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  49. package/src/adapters/cursor/cursor-errors.ts +129 -6
  50. package/src/adapters/cursor/discovery.ts +61 -4
  51. package/src/adapters/cursor/effort-map.ts +27 -3
  52. package/src/adapters/cursor/framing.ts +39 -0
  53. package/src/adapters/cursor/h2-pool.ts +123 -0
  54. package/src/adapters/cursor/http1-bidi.ts +361 -0
  55. package/src/adapters/cursor/images.ts +704 -0
  56. package/src/adapters/cursor/live-models.ts +174 -58
  57. package/src/adapters/cursor/live-transport.ts +609 -170
  58. package/src/adapters/cursor/native-exec-common.ts +23 -2
  59. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  60. package/src/adapters/cursor/native-exec-network.ts +1 -1
  61. package/src/adapters/cursor/native-exec-shell.ts +0 -1
  62. package/src/adapters/cursor/native-exec.ts +101 -14
  63. package/src/adapters/cursor/protobuf-events.ts +829 -11
  64. package/src/adapters/cursor/protobuf-request.ts +383 -65
  65. package/src/adapters/cursor/request-builder.ts +237 -31
  66. package/src/adapters/cursor/tool-definitions.ts +242 -12
  67. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  68. package/src/adapters/cursor/transport.ts +22 -0
  69. package/src/adapters/cursor/types.ts +28 -1
  70. package/src/adapters/cursor.ts +133 -7
  71. package/src/adapters/google-antigravity-replay.ts +558 -34
  72. package/src/adapters/google-antigravity-wire.ts +43 -10
  73. package/src/adapters/google-http.ts +38 -10
  74. package/src/adapters/google-tool-schema.ts +80 -15
  75. package/src/adapters/google-truncation.ts +11 -0
  76. package/src/adapters/google.ts +618 -74
  77. package/src/adapters/identity.ts +39 -6
  78. package/src/adapters/kiro-errors.ts +11 -0
  79. package/src/adapters/kiro-events.ts +19 -1
  80. package/src/adapters/kiro-thinking.ts +18 -2
  81. package/src/adapters/kiro-tools.ts +10 -1
  82. package/src/adapters/kiro.ts +92 -54
  83. package/src/adapters/mimo-free.ts +17 -0
  84. package/src/adapters/openai-chat-url.ts +11 -0
  85. package/src/adapters/openai-chat.ts +1311 -336
  86. package/src/adapters/openai-responses-url.ts +16 -0
  87. package/src/adapters/openai-responses.ts +830 -56
  88. package/src/adapters/registry.ts +175 -0
  89. package/src/adapters/responses-tool-schema.ts +67 -0
  90. package/src/adapters/tool-call-id.ts +119 -0
  91. package/src/adapters/tool-catalog-nudge.ts +104 -21
  92. package/src/adapters/xai-web-search.ts +185 -0
  93. package/src/bridge.ts +428 -61
  94. package/src/chat/inbound.ts +43 -19
  95. package/src/chat/outbound.ts +82 -26
  96. package/src/claude/agents-inject.ts +32 -9
  97. package/src/claude/context-windows.ts +21 -5
  98. package/src/claude/desktop-3p.ts +243 -9
  99. package/src/claude/gateway-cache.ts +41 -4
  100. package/src/claude/inbound.ts +72 -3
  101. package/src/claude/model-info.ts +38 -15
  102. package/src/claude/outbound.ts +70 -16
  103. package/src/cli/account-api.ts +35 -1
  104. package/src/cli/account-auth.ts +33 -6
  105. package/src/cli/account-catalog-refresh.ts +14 -0
  106. package/src/cli/account-extended.ts +389 -2
  107. package/src/cli/account-main.ts +317 -0
  108. package/src/cli/account.ts +30 -6
  109. package/src/cli/agent.ts +45 -1
  110. package/src/cli/claude-agent-startup-sync.ts +73 -0
  111. package/src/cli/claude-desktop.ts +29 -4
  112. package/src/cli/claude.ts +103 -34
  113. package/src/cli/codex-log-guard-doctor.ts +103 -0
  114. package/src/cli/codex-shim-autorestore.ts +2 -0
  115. package/src/cli/codex-shim-readiness.ts +76 -0
  116. package/src/cli/combo.ts +8 -0
  117. package/src/cli/config-command.ts +74 -10
  118. package/src/cli/dispatch.ts +593 -0
  119. package/src/cli/doctor.ts +315 -43
  120. package/src/cli/ensure-desired-integrations.ts +152 -0
  121. package/src/cli/export-command.ts +46 -20
  122. package/src/cli/help.ts +20 -271
  123. package/src/cli/index.ts +378 -519
  124. package/src/cli/init.ts +4 -17
  125. package/src/cli/integrations.ts +120 -2
  126. package/src/cli/lab.ts +607 -0
  127. package/src/cli/launcher-context.ts +77 -0
  128. package/src/cli/minimax.ts +497 -0
  129. package/src/cli/models-runtime.ts +35 -2
  130. package/src/cli/models.ts +100 -14
  131. package/src/cli/observe.ts +92 -3
  132. package/src/cli/opencode.ts +4 -2
  133. package/src/cli/provider-runtime.ts +18 -1
  134. package/src/cli/provider.ts +24 -3
  135. package/src/cli/ready.ts +301 -0
  136. package/src/cli/registry.ts +437 -0
  137. package/src/cli/root.ts +86 -0
  138. package/src/cli/route-policy.ts +92 -0
  139. package/src/cli/runtime-api.ts +6 -3
  140. package/src/cli/star-prompt.ts +71 -15
  141. package/src/cli/status.ts +10 -3
  142. package/src/cli/system-restart-client.ts +146 -0
  143. package/src/cli/tray-proxy.ts +153 -6
  144. package/src/cli/v2.ts +105 -10
  145. package/src/cli.ts +1 -1
  146. package/src/clients/config-export.ts +1358 -21
  147. package/src/codex/account-label.ts +14 -1
  148. package/src/codex/account-lifecycle.ts +130 -13
  149. package/src/codex/account-namespaces.ts +49 -3
  150. package/src/codex/account-priority.ts +83 -0
  151. package/src/codex/account-store.ts +29 -2
  152. package/src/codex/account-usability.ts +25 -2
  153. package/src/codex/admission.ts +256 -0
  154. package/src/codex/affinity-debug.ts +162 -0
  155. package/src/codex/app-server-processes.ts +493 -106
  156. package/src/codex/app-server-restart-service.ts +232 -0
  157. package/src/codex/auth-api.ts +849 -242
  158. package/src/codex/auth-collision.ts +5 -3
  159. package/src/codex/auth-context.ts +345 -32
  160. package/src/codex/autostart-health.ts +8 -1
  161. package/src/codex/catalog/account-models.ts +67 -0
  162. package/src/codex/catalog/aggregation.ts +68 -10
  163. package/src/codex/catalog/bundled.ts +331 -33
  164. package/src/codex/catalog/effort.ts +121 -30
  165. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  166. package/src/codex/catalog/kinds.ts +2 -0
  167. package/src/codex/catalog/metadata.ts +529 -45
  168. package/src/codex/catalog/native-models.ts +72 -0
  169. package/src/codex/catalog/parsing.ts +224 -30
  170. package/src/codex/catalog/provider-fetch.ts +1460 -134
  171. package/src/codex/catalog/sync.ts +1449 -186
  172. package/src/codex/catalog-admission.ts +199 -0
  173. package/src/codex/catalog-refresh-status.ts +105 -0
  174. package/src/codex/catalog-write-serialization.ts +242 -0
  175. package/src/codex/catalog.ts +6 -3
  176. package/src/codex/codex-write-lock.ts +384 -0
  177. package/src/codex/convergence-types.ts +614 -0
  178. package/src/codex/convergence.ts +651 -0
  179. package/src/codex/coordinator-doctor.ts +332 -0
  180. package/src/codex/custom-model-catalog-migration.ts +176 -0
  181. package/src/codex/desired-state.ts +230 -0
  182. package/src/codex/features.ts +636 -39
  183. package/src/codex/generation.ts +202 -0
  184. package/src/codex/history-job.ts +407 -0
  185. package/src/codex/history-lock.ts +242 -0
  186. package/src/codex/history-migration-guardian.ts +26 -20
  187. package/src/codex/history-provider.ts +231 -28
  188. package/src/codex/history-transition.ts +105 -0
  189. package/src/codex/history-worker.ts +220 -0
  190. package/src/codex/inject-coordination.ts +290 -0
  191. package/src/codex/inject.ts +1073 -152
  192. package/src/codex/injected-marker.ts +37 -3
  193. package/src/codex/integration-record.ts +266 -0
  194. package/src/codex/internal/catalog-writer.ts +203 -0
  195. package/src/codex/internal/history-writer.ts +80 -0
  196. package/src/codex/journal.ts +66 -4
  197. package/src/codex/log-guard/inspect.ts +506 -0
  198. package/src/codex/log-guard/lock.ts +150 -0
  199. package/src/codex/log-guard/maintenance.ts +403 -0
  200. package/src/codex/log-guard/path-safety.ts +88 -0
  201. package/src/codex/log-guard/policy.ts +44 -0
  202. package/src/codex/log-guard/processes.ts +205 -0
  203. package/src/codex/log-guard/protection.ts +489 -0
  204. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  205. package/src/codex/main-account-cache.ts +24 -0
  206. package/src/codex/main-account.ts +29 -1
  207. package/src/codex/management-convergence.ts +167 -0
  208. package/src/codex/model-cache.ts +56 -10
  209. package/src/codex/model-entitlements.ts +353 -0
  210. package/src/codex/native-main-admission.ts +47 -0
  211. package/src/codex/native-main-auth-temp.ts +187 -0
  212. package/src/codex/native-main-claim.ts +178 -0
  213. package/src/codex/native-main-lock-file.ts +162 -0
  214. package/src/codex/native-main-owner.ts +329 -0
  215. package/src/codex/native-profile-api.ts +247 -0
  216. package/src/codex/native-profile-manager.ts +1531 -0
  217. package/src/codex/native-profile-processes.ts +121 -0
  218. package/src/codex/native-profile-recovery.ts +99 -0
  219. package/src/codex/native-profile-stage-store.ts +387 -0
  220. package/src/codex/native-profile-startup.ts +492 -0
  221. package/src/codex/native-profile-store.ts +855 -0
  222. package/src/codex/native-profile-types.ts +120 -0
  223. package/src/codex/native-residue.ts +682 -0
  224. package/src/codex/paths.ts +80 -1
  225. package/src/codex/plan-from-token.ts +140 -0
  226. package/src/codex/plan.ts +40 -0
  227. package/src/codex/plugins-doctor.ts +1 -1
  228. package/src/codex/pool-rotation.ts +74 -4
  229. package/src/codex/project-config-warnings.ts +20 -6
  230. package/src/codex/prompt-journal.ts +352 -0
  231. package/src/codex/prompt-layers.ts +967 -0
  232. package/src/codex/prompt-lock.ts +143 -0
  233. package/src/codex/quota-rejection.ts +298 -0
  234. package/src/codex/quota.ts +175 -13
  235. package/src/codex/refresh.ts +11 -2
  236. package/src/codex/reset-credit-recovery.ts +1044 -0
  237. package/src/codex/routing.ts +505 -94
  238. package/src/codex/runtime.ts +159 -38
  239. package/src/codex/shim.ts +1009 -28
  240. package/src/codex/subagent-model-fallback.ts +350 -35
  241. package/src/codex/sync.ts +191 -2
  242. package/src/codex/transition-state.ts +612 -0
  243. package/src/codex/upstream-host-health.ts +368 -0
  244. package/src/codex/user-identity.ts +557 -0
  245. package/src/codex/warmup.ts +187 -81
  246. package/src/codex/write-coordination.ts +114 -0
  247. package/src/combos/failover.ts +20 -0
  248. package/src/combos/index.ts +4 -0
  249. package/src/combos/request.ts +32 -0
  250. package/src/combos/types.ts +81 -9
  251. package/src/config/provider-name.ts +24 -0
  252. package/src/config.ts +1762 -140
  253. package/src/generated/compatibility-version.json +3164 -0
  254. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  255. package/src/grok/inject.ts +16 -5
  256. package/src/grok/inspect.ts +45 -0
  257. package/src/grok/sync.ts +2 -2
  258. package/src/images/loop.ts +152 -29
  259. package/src/images/plan.ts +23 -13
  260. package/src/integrations/config-io.ts +269 -0
  261. package/src/integrations/journal.ts +315 -0
  262. package/src/integrations/merge.ts +135 -0
  263. package/src/integrations/mutation-flight.ts +71 -0
  264. package/src/integrations/native/ownership-preflight.ts +202 -0
  265. package/src/integrations/omp-yaml-source.ts +358 -0
  266. package/src/integrations/owned-refresh.ts +74 -0
  267. package/src/integrations/ownership.ts +111 -0
  268. package/src/integrations/registry.ts +159 -0
  269. package/src/integrations/serialize.ts +314 -0
  270. package/src/integrations/state.ts +361 -0
  271. package/src/integrations/store.ts +103 -0
  272. package/src/integrations/writer-lock.ts +98 -0
  273. package/src/integrations/writer.ts +691 -0
  274. package/src/lab/artifacts/sanitize.ts +586 -0
  275. package/src/lab/artifacts/secure-fs.ts +475 -0
  276. package/src/lab/artifacts/store.ts +310 -0
  277. package/src/lab/automation/budgets.ts +78 -0
  278. package/src/lab/automation/config-persistence.ts +256 -0
  279. package/src/lab/automation/constants.ts +39 -0
  280. package/src/lab/automation/cooldown.ts +103 -0
  281. package/src/lab/automation/dispatch.ts +211 -0
  282. package/src/lab/automation/index.ts +13 -0
  283. package/src/lab/automation/orchestrator.ts +499 -0
  284. package/src/lab/automation/persistence.ts +512 -0
  285. package/src/lab/automation/planner.ts +371 -0
  286. package/src/lab/automation/policy.ts +136 -0
  287. package/src/lab/automation/queue.ts +191 -0
  288. package/src/lab/automation/recovery.ts +24 -0
  289. package/src/lab/automation/route-context.ts +21 -0
  290. package/src/lab/automation/run-key.ts +44 -0
  291. package/src/lab/automation/runs-query.ts +34 -0
  292. package/src/lab/automation/types.ts +160 -0
  293. package/src/lab/conformance/assertion.ts +325 -0
  294. package/src/lab/conformance/digest.ts +22 -0
  295. package/src/lab/conformance/executor.ts +741 -0
  296. package/src/lab/conformance/fixture-provider.ts +27 -0
  297. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  298. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  299. package/src/lab/conformance/harness-budget.ts +47 -0
  300. package/src/lab/conformance/index.ts +5 -0
  301. package/src/lab/conformance/jcs.ts +64 -0
  302. package/src/lab/conformance/json-pointer.ts +39 -0
  303. package/src/lab/conformance/manifest.ts +180 -0
  304. package/src/lab/conformance/mcp-stub.ts +179 -0
  305. package/src/lab/conformance/negative-controls.ts +164 -0
  306. package/src/lab/conformance/observation.ts +355 -0
  307. package/src/lab/conformance/runner.ts +68 -0
  308. package/src/lab/conformance/sse-normalize.ts +59 -0
  309. package/src/lab/conformance/suite-manifest.ts +78 -0
  310. package/src/lab/conformance/types.ts +214 -0
  311. package/src/lab/constants.ts +126 -0
  312. package/src/lab/digest.ts +64 -0
  313. package/src/lab/events/errors.ts +9 -0
  314. package/src/lab/events/limits.ts +117 -0
  315. package/src/lab/events/types.ts +229 -0
  316. package/src/lab/events/validate.ts +781 -0
  317. package/src/lab/fabric/constants.ts +40 -0
  318. package/src/lab/fabric/executor.ts +492 -0
  319. package/src/lab/fabric/index.ts +80 -0
  320. package/src/lab/fabric/manifest.ts +222 -0
  321. package/src/lab/fabric/observe.ts +489 -0
  322. package/src/lab/fabric/patch.ts +79 -0
  323. package/src/lab/fabric/producer-child.ts +139 -0
  324. package/src/lab/fabric/producer-isolate.ts +276 -0
  325. package/src/lab/fabric/producer-protocol.ts +61 -0
  326. package/src/lab/fabric/scratch.ts +439 -0
  327. package/src/lab/fabric/subject.ts +106 -0
  328. package/src/lab/fabric/types.ts +134 -0
  329. package/src/lab/fabric/verifier.ts +98 -0
  330. package/src/lab/index.ts +54 -0
  331. package/src/lab/ledger/artifact-refs.ts +127 -0
  332. package/src/lab/ledger/invalidation.ts +136 -0
  333. package/src/lab/ledger/purge.ts +310 -0
  334. package/src/lab/ledger/store.ts +532 -0
  335. package/src/lab/live/credential-lease.ts +53 -0
  336. package/src/lab/live/destination.ts +155 -0
  337. package/src/lab/live/executor.ts +336 -0
  338. package/src/lab/live/inert-tools.ts +56 -0
  339. package/src/lab/live/manifest.ts +85 -0
  340. package/src/lab/live/mcp-loopback.ts +57 -0
  341. package/src/lab/live/runner.ts +19 -0
  342. package/src/lab/live/sandbox.ts +61 -0
  343. package/src/lab/live/suite-manifest.ts +41 -0
  344. package/src/lab/live/transport.ts +118 -0
  345. package/src/lab/live/types.ts +197 -0
  346. package/src/lab/observe/from-conformance.ts +301 -0
  347. package/src/lab/observe/from-live.ts +117 -0
  348. package/src/lab/paths.ts +153 -0
  349. package/src/lab/projection/rebuild.ts +495 -0
  350. package/src/lab/projection/schema.ts +135 -0
  351. package/src/lab/projection/verdicts.ts +474 -0
  352. package/src/lab/projection/verification.ts +412 -0
  353. package/src/lab/public/bundle.ts +217 -0
  354. package/src/lab/public/community-authority.ts +175 -0
  355. package/src/lab/public/community-files.ts +29 -0
  356. package/src/lab/public/community.ts +479 -0
  357. package/src/lab/public/file-safety.ts +155 -0
  358. package/src/lab/public/ids.ts +26 -0
  359. package/src/lab/public/index.ts +16 -0
  360. package/src/lab/public/mutation-lock.ts +424 -0
  361. package/src/lab/public/operator.ts +353 -0
  362. package/src/lab/public/origin-purge.ts +79 -0
  363. package/src/lab/public/origin.ts +203 -0
  364. package/src/lab/public/privacy.ts +143 -0
  365. package/src/lab/public/private-file.ts +261 -0
  366. package/src/lab/public/project.ts +124 -0
  367. package/src/lab/public/purge-test-fault.ts +21 -0
  368. package/src/lab/public/purge.ts +223 -0
  369. package/src/lab/public/registry.ts +44 -0
  370. package/src/lab/public/revocation.ts +252 -0
  371. package/src/lab/public/signature.ts +243 -0
  372. package/src/lab/public/storage.ts +105 -0
  373. package/src/lab/public/strict-json.ts +206 -0
  374. package/src/lab/public/time.ts +26 -0
  375. package/src/lab/public/types.ts +172 -0
  376. package/src/lab/public/validate.ts +391 -0
  377. package/src/lab/query/catalog.ts +101 -0
  378. package/src/lab/query/connection.ts +107 -0
  379. package/src/lab/query/constants.ts +4 -0
  380. package/src/lab/query/cursor.ts +132 -0
  381. package/src/lab/query/dto-map.ts +277 -0
  382. package/src/lab/query/errors.ts +22 -0
  383. package/src/lab/query/freshness.ts +53 -0
  384. package/src/lab/query/index.ts +45 -0
  385. package/src/lab/query/latest-observation.ts +59 -0
  386. package/src/lab/query/passive-production.ts +159 -0
  387. package/src/lab/query/queries.ts +444 -0
  388. package/src/lab/query/types.ts +266 -0
  389. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  390. package/src/lab/subject/installation-salt.ts +112 -0
  391. package/src/lab/subject/protocol-subject.ts +80 -0
  392. package/src/lab/subject/route-subject.ts +74 -0
  393. package/src/lib/app-owned-memory-stores.ts +22 -0
  394. package/src/lib/bounded-body.ts +153 -9
  395. package/src/lib/bun-runtime.ts +125 -12
  396. package/src/lib/bun-stream-caps.ts +13 -9
  397. package/src/lib/codex-restart-contract.ts +120 -0
  398. package/src/lib/config-ownership.ts +6 -2
  399. package/src/lib/destination-policy.ts +65 -1
  400. package/src/lib/errors.ts +44 -2
  401. package/src/lib/fabric-task-execution-authority.ts +7 -0
  402. package/src/lib/fabric-task-host.ts +29 -0
  403. package/src/lib/lab-activation.ts +223 -0
  404. package/src/lib/lab-live-execution-authority.ts +13 -0
  405. package/src/lib/lab-live-host.ts +30 -0
  406. package/src/lib/lab-live-pinned-sender.ts +56 -0
  407. package/src/lib/lab-live-route-production.ts +130 -0
  408. package/src/lib/lab-passive-linker-registration.ts +26 -0
  409. package/src/lib/local-management-attestation.ts +51 -0
  410. package/src/lib/local-management-capability.ts +100 -0
  411. package/src/lib/local-provider-reload-contract.ts +100 -0
  412. package/src/lib/optional-shutdown-hooks.ts +57 -0
  413. package/src/lib/pinned-http.ts +145 -26
  414. package/src/lib/process-control.ts +4 -1
  415. package/src/lib/provider-outbound.ts +49 -9
  416. package/src/lib/redact.ts +419 -3
  417. package/src/lib/self-launch-argv.ts +15 -0
  418. package/src/lib/server-resource-ownership.ts +71 -0
  419. package/src/lib/shadow-call.ts +35 -4
  420. package/src/lib/sse-decoder.ts +41 -0
  421. package/src/lib/state-store-registrations.ts +10 -2
  422. package/src/lib/system-restart-contract.ts +73 -0
  423. package/src/lib/token-estimate.ts +19 -2
  424. package/src/lib/tool-argument-integers.ts +202 -0
  425. package/src/lib/translator-budget.ts +44 -0
  426. package/src/lib/upstream-http-version.ts +57 -0
  427. package/src/lib/upstream-reachability.ts +95 -0
  428. package/src/lib/upstream-retry.ts +156 -3
  429. package/src/lib/windows-atomic-replace.ts +155 -0
  430. package/src/lib/windows-elevation.ts +70 -2
  431. package/src/lib/windows-secret-acl.ts +409 -69
  432. package/src/lib/windows-service-wrappers.ts +72 -0
  433. package/src/lib/windows-text.ts +106 -0
  434. package/src/lib/windows-user-principal.ts +341 -0
  435. package/src/lib/winsw.ts +33 -5
  436. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  437. package/src/oauth/account-import/index.ts +15 -0
  438. package/src/oauth/account-import/parser.ts +83 -0
  439. package/src/oauth/account-import/registry.ts +18 -0
  440. package/src/oauth/account-import/service.ts +75 -0
  441. package/src/oauth/account-import/types.ts +91 -0
  442. package/src/oauth/anthropic.ts +12 -1
  443. package/src/oauth/callback-server.ts +8 -2
  444. package/src/oauth/chatgpt.ts +12 -1
  445. package/src/oauth/command-code.ts +239 -0
  446. package/src/oauth/cursor.ts +46 -5
  447. package/src/oauth/google-antigravity.ts +35 -3
  448. package/src/oauth/health.ts +20 -12
  449. package/src/oauth/index.ts +398 -66
  450. package/src/oauth/key-providers.ts +16 -0
  451. package/src/oauth/kimi.ts +16 -2
  452. package/src/oauth/kiro.ts +50 -6
  453. package/src/oauth/local-token-detect.ts +11 -2
  454. package/src/oauth/log.ts +3 -1
  455. package/src/oauth/login-cli.ts +88 -28
  456. package/src/oauth/nous.ts +798 -0
  457. package/src/oauth/store.ts +119 -21
  458. package/src/oauth/token-guardian.ts +9 -3
  459. package/src/pi/models.ts +2 -2
  460. package/src/providers/alibaba-region-migration.ts +1 -1
  461. package/src/providers/antigravity-models.ts +521 -31
  462. package/src/providers/base-url-choices.ts +10 -0
  463. package/src/providers/codex-capacity.ts +292 -0
  464. package/src/providers/command-code-efforts.ts +144 -0
  465. package/src/providers/context-cap.ts +22 -5
  466. package/src/providers/cursor-pool.ts +72 -0
  467. package/src/providers/derive.ts +253 -6
  468. package/src/providers/fastwire.ts +501 -0
  469. package/src/providers/free-directory.ts +10 -7
  470. package/src/providers/google-vertex-location.ts +14 -0
  471. package/src/providers/key-failover.ts +71 -3
  472. package/src/providers/label.ts +1 -1
  473. package/src/providers/model-discovery-limits.ts +16 -0
  474. package/src/providers/model-discovery.ts +115 -22
  475. package/src/providers/model-rename-migration.ts +255 -0
  476. package/src/providers/model-rename-startup.ts +28 -0
  477. package/src/providers/openai-sidecar.ts +72 -4
  478. package/src/providers/openai-tier-startup.ts +31 -2
  479. package/src/providers/openai-tiers.ts +119 -4
  480. package/src/providers/openai-virtual-models.ts +1 -0
  481. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  482. package/src/providers/provider-id-rewrite.ts +29 -0
  483. package/src/providers/quota.ts +1319 -38
  484. package/src/providers/registry.ts +1429 -111
  485. package/src/providers/request-pacing.ts +310 -0
  486. package/src/providers/service-tier.ts +277 -0
  487. package/src/providers/slug-codec.ts +42 -6
  488. package/src/providers/static-model-discovery.ts +86 -0
  489. package/src/providers/xai-responses-opt-in.ts +15 -0
  490. package/src/providers/xai-transport.ts +11 -4
  491. package/src/reasoning-effort.ts +49 -1
  492. package/src/responses/compaction.ts +26 -1
  493. package/src/responses/custom-tool-compat.ts +266 -0
  494. package/src/responses/hosted-tool-policy.ts +9 -0
  495. package/src/responses/namespace-tool-compat.ts +355 -0
  496. package/src/responses/parser.ts +220 -38
  497. package/src/responses/provider-continuation.ts +98 -0
  498. package/src/responses/provider-opaque-metadata.ts +73 -0
  499. package/src/responses/reasoning-envelope.ts +9 -1
  500. package/src/responses/reasoning-replay-cache.ts +426 -0
  501. package/src/responses/schema.ts +7 -1
  502. package/src/responses/spill-store.ts +75 -10
  503. package/src/responses/state.ts +565 -27
  504. package/src/responses/thought-signature-replay.ts +347 -0
  505. package/src/responses/tool-search-compat.ts +301 -0
  506. package/src/responses/truncated-stop-reason.ts +60 -0
  507. package/src/router.ts +366 -30
  508. package/src/routing/analytics.ts +378 -0
  509. package/src/routing/capability.ts +244 -0
  510. package/src/routing/compatibility/assemble.ts +73 -0
  511. package/src/routing/compatibility/behavior.ts +278 -0
  512. package/src/routing/compatibility/catalog.ts +99 -0
  513. package/src/routing/compatibility/endpoint.ts +52 -0
  514. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  515. package/src/routing/compatibility/policy.ts +181 -0
  516. package/src/routing/compatibility/provider-slot.ts +56 -0
  517. package/src/routing/compatibility/reader.ts +110 -0
  518. package/src/routing/compatibility/subject.ts +191 -0
  519. package/src/routing/compatibility/types.ts +64 -0
  520. package/src/routing/compatibility/version.ts +104 -0
  521. package/src/routing/cost.ts +77 -0
  522. package/src/routing/evaluator.ts +495 -0
  523. package/src/routing/health.ts +412 -0
  524. package/src/routing/history/cursor.ts +43 -0
  525. package/src/routing/history/indexer.ts +605 -0
  526. package/src/routing/history/schema.ts +72 -0
  527. package/src/routing/profile-namespace.ts +15 -0
  528. package/src/routing/profile.ts +547 -0
  529. package/src/routing/quota.ts +145 -0
  530. package/src/routing/request-evidence.ts +45 -0
  531. package/src/routing/trace.ts +776 -0
  532. package/src/server/adapter-resolve.ts +2 -29
  533. package/src/server/auth-cors.ts +267 -46
  534. package/src/server/background-lifecycle.ts +182 -0
  535. package/src/server/chat-completions.ts +130 -56
  536. package/src/server/chat-native-sse.ts +331 -0
  537. package/src/server/chat-native.ts +426 -0
  538. package/src/server/claude-messages.ts +159 -43
  539. package/src/server/direct-local-http.ts +347 -0
  540. package/src/server/effort-policy.ts +18 -0
  541. package/src/server/github-copilot-responses-repair.ts +338 -0
  542. package/src/server/gui-static.ts +39 -10
  543. package/src/server/images.ts +94 -12
  544. package/src/server/index.ts +865 -181
  545. package/src/server/lifecycle.ts +284 -13
  546. package/src/server/live.ts +136 -17
  547. package/src/server/local-management-read-client.ts +90 -0
  548. package/src/server/local-provider-reload-client.ts +137 -0
  549. package/src/server/management/agent-settings-routes.ts +398 -103
  550. package/src/server/management/api-key-usage.ts +31 -5
  551. package/src/server/management/body.ts +6 -0
  552. package/src/server/management/combo-routes.ts +62 -24
  553. package/src/server/management/config-routes.ts +464 -51
  554. package/src/server/management/context.ts +80 -2
  555. package/src/server/management/integration-routes.ts +498 -0
  556. package/src/server/management/lab-automation-routes.ts +206 -0
  557. package/src/server/management/lab-routes.ts +563 -0
  558. package/src/server/management/logs-usage-routes.ts +101 -32
  559. package/src/server/management/model-routes.ts +189 -131
  560. package/src/server/management/model-rows.ts +163 -0
  561. package/src/server/management/native-integration-routes.ts +769 -0
  562. package/src/server/management/oauth-account-routes.ts +80 -4
  563. package/src/server/management/provider-capability-config.ts +48 -0
  564. package/src/server/management/provider-routes.ts +764 -157
  565. package/src/server/management/request-history-routes.ts +191 -0
  566. package/src/server/management/routing-analytics-routes.ts +74 -0
  567. package/src/server/management/routing-profile-routes.ts +380 -0
  568. package/src/server/management/shared.ts +27 -11
  569. package/src/server/management/sidebar-routes.ts +47 -31
  570. package/src/server/management/storage-log-guard-routes.ts +186 -0
  571. package/src/server/management/sync-response.ts +69 -0
  572. package/src/server/management/system-restart.ts +288 -32
  573. package/src/server/management/system-routes.ts +77 -0
  574. package/src/server/management/usage-summary-cache.ts +9 -1
  575. package/src/server/management/vision-sidecar-options.ts +167 -0
  576. package/src/server/management/web-search-sidecar-options.ts +120 -0
  577. package/src/server/management-api.ts +115 -14
  578. package/src/server/management-auth.ts +220 -5
  579. package/src/server/passive-route-linker.ts +66 -0
  580. package/src/server/ports.ts +41 -1
  581. package/src/server/proxy-liveness.ts +132 -5
  582. package/src/server/readiness.ts +99 -0
  583. package/src/server/relay-eager.ts +82 -42
  584. package/src/server/relay.ts +236 -76
  585. package/src/server/request-decompress.ts +113 -6
  586. package/src/server/request-log.ts +235 -22
  587. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  588. package/src/server/responses/agent-task-recovery.ts +465 -0
  589. package/src/server/responses/collaboration.ts +204 -35
  590. package/src/server/responses/compact.ts +442 -55
  591. package/src/server/responses/core.ts +2872 -331
  592. package/src/server/responses/empty-completion-guard.ts +276 -0
  593. package/src/server/responses/encrypted-payload.ts +62 -39
  594. package/src/server/responses/fetch-helpers.ts +79 -4
  595. package/src/server/responses/input-admission.ts +185 -0
  596. package/src/server/responses/pacing-overload.ts +13 -0
  597. package/src/server/responses/policy-fallback.ts +178 -0
  598. package/src/server/responses/responses-field-backfill.ts +251 -0
  599. package/src/server/responses/terminal-guard.ts +26 -5
  600. package/src/server/responses/upstream-error.ts +5 -0
  601. package/src/server/responses/ws-upstream.ts +308 -0
  602. package/src/server/responses-custom-tool-repair.ts +282 -0
  603. package/src/server/responses-item-id-repair.ts +54 -6
  604. package/src/server/responses-json-events.ts +90 -0
  605. package/src/server/responses-model-rewrite.ts +29 -0
  606. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  607. package/src/server/responses-snapshot-repair.ts +621 -0
  608. package/src/server/responses-terminal-repair.ts +342 -0
  609. package/src/server/responses-tool-search-repair.ts +267 -0
  610. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  611. package/src/server/responses.ts +18 -2
  612. package/src/server/search.ts +78 -13
  613. package/src/server/sse-frame-buffer.ts +292 -0
  614. package/src/server/sse-payload-rewrite.ts +110 -22
  615. package/src/server/startup-action-control.ts +8 -1
  616. package/src/server/startup-health-cache.ts +19 -1
  617. package/src/server/system-env.ts +80 -9
  618. package/src/server/ws-bridge.ts +39 -38
  619. package/src/service-manager-probe.ts +892 -0
  620. package/src/service.ts +1111 -90
  621. package/src/sidecar/auth.ts +92 -0
  622. package/src/sidecar/candidates.ts +83 -0
  623. package/src/storage/cleanup.ts +2 -2
  624. package/src/storage/scanner.ts +1 -1
  625. package/src/storage/worker-lifecycle.ts +14 -14
  626. package/src/tray/windows-tray.ps1 +83 -9
  627. package/src/tray/windows.ts +43 -16
  628. package/src/types/accounts.ts +37 -0
  629. package/src/types/config.ts +845 -0
  630. package/src/types/provider.ts +545 -0
  631. package/src/types/request.ts +384 -0
  632. package/src/types/tools.ts +131 -0
  633. package/src/types/wire.ts +80 -0
  634. package/src/types.ts +104 -1236
  635. package/src/update/index.ts +32 -19
  636. package/src/update/job.ts +442 -67
  637. package/src/update/notify.ts +12 -6
  638. package/src/update/npm-cache-preflight.d.mts +47 -0
  639. package/src/update/npm-cache-preflight.mjs +201 -0
  640. package/src/update/transactional-install.d.mts +22 -0
  641. package/src/update/transactional-install.mjs +259 -0
  642. package/src/usage/cost.ts +0 -0
  643. package/src/usage/expected-prices.ts +268 -16
  644. package/src/usage/log.ts +606 -41
  645. package/src/usage/summary.ts +177 -9
  646. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  647. package/src/usage/user-cost-overlays.ts +314 -0
  648. package/src/vision/anthropic-describe.ts +10 -6
  649. package/src/vision/backends.ts +97 -0
  650. package/src/vision/describe.ts +9 -3
  651. package/src/vision/eligibility.ts +250 -0
  652. package/src/vision/index.ts +238 -24
  653. package/src/vision/reasoning.ts +55 -0
  654. package/src/vision/routed-describe.ts +175 -0
  655. package/src/vision/timeout-bounds.ts +9 -0
  656. package/src/web-search/anthropic-executor.ts +13 -7
  657. package/src/web-search/backends.ts +108 -0
  658. package/src/web-search/exa-executor.ts +88 -0
  659. package/src/web-search/executor.ts +11 -3
  660. package/src/web-search/gemini-executor.ts +141 -0
  661. package/src/web-search/index.ts +150 -15
  662. package/src/web-search/loop.ts +279 -50
  663. package/src/web-search/parse.ts +125 -30
  664. package/src/web-search/sources.ts +60 -0
  665. package/src/web-search/xai-executor.ts +219 -0
  666. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  667. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  668. package/gui/dist/provider-icons/antigravity.svg +0 -1
  669. package/gui/dist/provider-icons/claude.svg +0 -1
  670. package/gui/dist/provider-icons/copilot.svg +0 -1
  671. package/gui/dist/provider-icons/cursor.svg +0 -2
  672. package/gui/dist/provider-icons/gemini.svg +0 -1
  673. package/gui/dist/provider-icons/grok-color.svg +0 -1
  674. package/gui/dist/provider-icons/kiro.svg +0 -14
  675. package/src/cli/internal-dispatch.ts +0 -20
@@ -9,19 +9,38 @@ import type {
9
9
  OcxThinkingContent,
10
10
  OcxTool,
11
11
  OcxToolCall,
12
+ OcxReasoningReplayScopeRef,
12
13
  } from "../types";
13
- import { namespacedToolName } from "../types";
14
+ import { namespacedToolName, toolChoiceCandidates } 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 }
@@ -151,43 +170,53 @@ function buildTools(tools: unknown[] | undefined): OcxTool[] | undefined {
151
170
  if (namespace) tool.namespace = namespace;
152
171
  out.push(tool);
153
172
  };
173
+ const pushCustom = (t: Record<string, unknown>, namespace?: string) => {
174
+ // Freeform custom tools are lowered to a single string `input` because chat models cannot
175
+ // emit Responses grammar payloads directly. Keep tool-specific input guidance scoped to the
176
+ // tool that owns it: leaking apply_patch syntax into `exec` or another freeform tool teaches
177
+ // routed models that the nested helper name is itself a callable top-level tool.
178
+ const inputDescription = t.name === "apply_patch"
179
+ ? "Raw tool input. For apply_patch, begin exactly with `*** Begin Patch` (no trailing `***`), then use its standard patch envelope."
180
+ : "Raw freeform input for this tool.";
181
+ const tool: OcxTool = {
182
+ name: t.name as string,
183
+ description: (t.description as string) ?? "",
184
+ parameters: { type: "object", properties: { input: { type: "string", description: inputDescription } }, required: ["input"] },
185
+ freeform: true,
186
+ };
187
+ if (namespace) tool.namespace = namespace;
188
+ out.push(tool);
189
+ };
154
190
  for (const t of tools) {
155
191
  if (!isObj(t)) continue;
192
+ if (t.type === "function" && isObj(t.function) && typeof t.function.name === "string" && t.function.name.length > 0) {
193
+ pushFn(t.function as Record<string, unknown>);
194
+ continue;
195
+ }
156
196
  if (t.type === "function" && typeof t.name === "string") {
157
197
  pushFn(t);
158
198
  } 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;
199
+ // Codex 0.147 groups its ordinary client tools under the reserved `functions` namespace,
200
+ // including freeform custom tools such as code-mode `exec`. Those children are still
201
+ // top-level Responses tools, so flatten them without a namespace. Other namespace groups
202
+ // are MCP-style and keep their namespace for round-trip routing.
203
+ const builtinFunctions = t.name === "functions";
204
+ const ns = typeof t.name === "string" && !builtinFunctions ? t.name : undefined;
162
205
  for (const inner of t.tools as unknown[]) {
163
206
  if (isObj(inner) && inner.type === "function" && typeof inner.name === "string") pushFn(inner, ns);
207
+ else if (isObj(inner) && inner.type === "custom" && typeof inner.name === "string") pushCustom(inner, ns);
164
208
  }
165
209
  }
166
210
  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
- });
211
+ pushCustom(t);
176
212
  }
177
213
  else if (t.type === "tool_search") {
178
214
  // Client-executed tool discovery — the gateway to deferred tools (subagents, extra MCP tools).
179
215
  // Expose as a function so chat models can call it; the bridge relays it as a tool_search_call.
180
216
  out.push({
181
217
  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>,
218
+ description: toolSearchDescription(t),
219
+ parameters: normalizeParameters(toolSearchParameters(t)),
191
220
  toolSearch: true,
192
221
  });
193
222
  }
@@ -263,9 +292,70 @@ function findToolById(messages: OcxMessage[], callId: string): { name: string; n
263
292
  return { name: "" };
264
293
  }
265
294
 
295
+ /**
296
+ * Attach pending reasoning to the assistant turn that owns the given call id.
297
+ * Reconstructed histories (resume/retry/synthetic) can order a `reasoning`
298
+ * item AFTER the `function_call` it belongs to; without this, the pending
299
+ * buffer is cleared at the tool output and the turn serializes without
300
+ * `reasoning_content`, which DeepSeek thinking mode rejects with HTTP 400
301
+ * (issue #950).
302
+ */
303
+ function attachPendingReasoningToCallOwner(
304
+ messages: OcxMessage[],
305
+ callId: string,
306
+ pendingReasoning: Array<{ part: OcxThinkingContent; envelopeSigned: boolean }>,
307
+ ): void {
308
+ if (pendingReasoning.length === 0 || !callId) return;
309
+ for (let i = messages.length - 1; i >= 0; i--) {
310
+ const m = messages[i];
311
+ if (m.role !== "assistant") continue;
312
+ for (const part of m.content) {
313
+ if (part.type === "toolCall" && part.id === callId) {
314
+ // Prepend so thinking still precedes tool_use for adapters that require
315
+ // that ordering (Anthropic-style replay).
316
+ m.content = [...pendingReasoning.map(entry => entry.part), ...m.content];
317
+ return;
318
+ }
319
+ }
320
+ }
321
+ }
322
+
266
323
  const REASONING_EFFORTS = new Set(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
267
324
 
268
- export function parseRequest(body: unknown): OcxParsedRequest {
325
+ /**
326
+ * Namespace a custom tool was declared under, by its bare name.
327
+ *
328
+ * A `custom_tool_call` echoed back by the client carries only the bare name — the bridge
329
+ * emits `{"type":"custom_tool_call","name":"exec"}` even when the tool was declared as
330
+ * `mcp__functions__exec`. Without this lookup the namespace is lost on the return trip,
331
+ * and the adapters replay history through `namespacedToolName(namespace, name)`, which
332
+ * then produces a bare `exec` the provider may not have. Ordinary `function_call` items
333
+ * do not need this: they carry `namespace` on the wire.
334
+ */
335
+ function customToolNamespaces(tools: unknown): Map<string, string> {
336
+ const out = new Map<string, string>();
337
+ if (!Array.isArray(tools)) return out;
338
+ for (const spec of tools) {
339
+ if (!isObj(spec) || spec.type !== "namespace" || !Array.isArray(spec.tools)) continue;
340
+ const namespace = typeof spec.name === "string" ? spec.name : undefined;
341
+ // Codex 0.147 groups ordinary client tools under the reserved `functions` namespace and
342
+ // buildTools deliberately flattens those without a namespace. Mirror that here, or the
343
+ // reconstruction would invent a namespace the request never advertised.
344
+ if (!namespace || namespace === "functions") continue;
345
+ for (const inner of spec.tools) {
346
+ if (!isObj(inner) || inner.type !== "custom" || typeof inner.name !== "string") continue;
347
+ // Ambiguous bare names are already rejected upstream, so first declaration wins.
348
+ if (!out.has(inner.name)) out.set(inner.name, namespace);
349
+ }
350
+ }
351
+ return out;
352
+ }
353
+
354
+ export function parseRequest(
355
+ body: unknown,
356
+ parseOptions?: { replayCacheScope?: OcxReasoningReplayScopeRef },
357
+ ): OcxParsedRequest {
358
+ const replayCacheScope = parseOptions?.replayCacheScope;
269
359
  const replayedInputPrefixLength = previousResponseReplayPrefixLength(body);
270
360
  const parsed = responsesRequestSchema.safeParse(body);
271
361
  if (!parsed.success) {
@@ -274,6 +364,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
274
364
  const data = parsed.data;
275
365
  const now = Date.now();
276
366
  const messages: OcxMessage[] = [];
367
+ // Built before the item loop: a custom_tool_call echoed back in `input` needs the
368
+ // namespace from the request's own tool catalog to survive the round trip.
369
+ const customToolNamespacesByName = customToolNamespaces(data.tools);
277
370
  const systemPrompt: string[] = [];
278
371
  // Responses reasoning siblings belong to the following assistant, including across call items.
279
372
  // Keep them off the message list until that assistant arrives; turn boundaries clear the array.
@@ -296,17 +389,33 @@ export function parseRequest(body: unknown): OcxParsedRequest {
296
389
  // synthetic `{type:"compaction"}` output item (src/responses/compaction.ts). Flagged for the server.
297
390
  let compactionRequest = false;
298
391
  let contextCompactionBoundary = false;
392
+ let continuationConversationMessageIndex: number | undefined;
299
393
 
300
394
  if (typeof data.instructions === "string" && data.instructions.length > 0) {
301
395
  systemPrompt.push(data.instructions);
302
396
  }
303
397
 
304
398
  if (typeof data.input === "string") {
399
+ if (data.previous_response_id) continuationConversationMessageIndex = messages.length;
305
400
  messages.push({ role: "user", content: data.input, timestamp: now });
306
401
  } else if (data.input) {
307
402
  for (let inputIndex = 0; inputIndex < data.input.length; inputIndex++) {
308
403
  const item = data.input[inputIndex];
309
404
  const effectiveType = (item as { type?: string }).type ?? ("role" in item ? "message" : undefined);
405
+ const itemRole = (item as { role?: string }).role;
406
+ // Raw protocol items do not map one-to-one onto context messages. Capture the boundary while
407
+ // both representations are available so later metadata can stay before conversation in both.
408
+ if (
409
+ data.previous_response_id
410
+ && inputIndex >= replayedInputPrefixLength
411
+ && continuationConversationMessageIndex === undefined
412
+ && (
413
+ effectiveType === "agent_message"
414
+ || (effectiveType === "message" && (itemRole === "user" || itemRole === "assistant"))
415
+ )
416
+ ) {
417
+ continuationConversationMessageIndex = messages.length;
418
+ }
310
419
 
311
420
  if (effectiveType === "compaction_trigger") {
312
421
  compactionRequest = true;
@@ -325,7 +434,7 @@ export function parseRequest(body: unknown): OcxParsedRequest {
325
434
  continue;
326
435
  }
327
436
 
328
- if (effectiveType === "compaction" || effectiveType === "compaction_summary" || effectiveType === "context_compaction") {
437
+ if (isCompactionItemType(effectiveType)) {
329
438
  // A stored summary from a previous compaction. Decode our ocx1 envelope into plain text so
330
439
  // the routed model keeps the compacted context; real OpenAI-encrypted blobs degrade to a note.
331
440
  // `context_compaction` (encrypted_content optional) is codex-rs's local-compaction marker;
@@ -416,6 +525,18 @@ export function parseRequest(body: unknown): OcxParsedRequest {
416
525
  : null;
417
526
  const thinkingText = envelope?.txt || text;
418
527
 
528
+ // Kiro reasoning round-trip: a krc-only item carries nothing renderable — it is provider
529
+ // state for the assistant turn that ALREADY closed, because Kiro emits its
530
+ // reasoningContentEvent at the END of a turn (after content AND tool calls, verified
531
+ // against kiro-cli 2.14.1/2.16.0). Folding it into the FOLLOWING turn like ordinary
532
+ // reasoning would attach turn N's blob to turn N+1, so attach it backwards instead. With
533
+ // no assistant turn to own it the blob is dropped rather than mis-paired.
534
+ if (envelope?.krc && thinkingText.length === 0) {
535
+ const previous = messages[messages.length - 1];
536
+ if (previous?.role === "assistant") previous.kiroRedactedReasoning = envelope.krc;
537
+ continue;
538
+ }
539
+
419
540
  // Native/non-ocxr1 encrypted-only reasoning is opaque here. Do not create a detached
420
541
  // assistant turn or invent replayable plaintext/signatures from the encrypted payload.
421
542
  if (thinkingText.length > 0) {
@@ -442,7 +563,7 @@ export function parseRequest(body: unknown): OcxParsedRequest {
442
563
  }
443
564
 
444
565
  if (effectiveType === "function_call") {
445
- const call = item as { id?: string; call_id: string; name: string; arguments?: string; namespace?: string };
566
+ const call = item as { id?: string; call_id: string; name: string; arguments?: string; namespace?: string; extra_content?: unknown };
446
567
  // Tolerate empty/non-JSON arguments (e.g. a no-arg tool call serialized as "") instead of
447
568
  // throwing — a single poisoned history item would otherwise 400 every subsequent turn.
448
569
  let args: Record<string, unknown> = {};
@@ -463,16 +584,32 @@ export function parseRequest(body: unknown): OcxParsedRequest {
463
584
  type: "toolCall", id: call.call_id, name: call.name, arguments: args,
464
585
  ...(call.namespace ? { namespace: call.namespace } : {}),
465
586
  };
587
+ // Provider-opaque metadata (e.g. a Gemini thought signature) travels with the call so a
588
+ // history-replayed or previous_response_id turn rebuilds the same signed part instead of
589
+ // depending on the same-process replay cache (issue #1735). Real clients do not echo
590
+ // extra_content on replay, so fall back to the proxy-side store keyed by call_id.
591
+ const providerMetadata = providerMetadataFromResponsesFunctionCall(call)
592
+ ?? (typeof call.call_id === "string"
593
+ ? replayThoughtSignatureMetadata(call.call_id, replayCacheScope)
594
+ : undefined);
595
+ if (providerMetadata) toolCall.providerMetadata = providerMetadata;
466
596
  assistantHolderWithReasoning().content.push(toolCall);
467
597
  continue;
468
598
  }
469
599
 
470
600
  if (effectiveType === "custom_tool_call") {
471
601
  const call = item as { id?: string; call_id: string; name: string; input: string };
602
+ const remembered = typeof call.call_id === "string" ? replayThoughtSignatureMetadata(call.call_id, replayCacheScope) : undefined;
603
+ // Reconstruct the namespace the request declared this tool under. The wire item
604
+ // carries only the bare name, so without this the round trip loses it and adapters
605
+ // replay the call as an unnamespaced tool the provider may not expose.
606
+ const customNamespace = customToolNamespacesByName.get(call.name);
472
607
  const toolCall: OcxToolCall = {
473
608
  type: "toolCall", id: call.call_id, name: call.name,
474
609
  arguments: { input: call.input ?? "" },
475
610
  customWireName: call.name,
611
+ ...(customNamespace ? { namespace: customNamespace } : {}),
612
+ ...(remembered ? { providerMetadata: remembered } : {}),
476
613
  };
477
614
  assistantHolderWithReasoning().content.push(toolCall);
478
615
  continue;
@@ -485,9 +622,11 @@ export function parseRequest(body: unknown): OcxParsedRequest {
485
622
  const callId = call.call_id ?? call.id;
486
623
  if (callId) {
487
624
  const command = Array.isArray(call.action?.command) ? call.action.command : [];
625
+ const remembered = replayThoughtSignatureMetadata(callId, replayCacheScope);
488
626
  assistantHolderWithReasoning().content.push({
489
627
  type: "toolCall", id: callId, name: "shell",
490
628
  arguments: command.length > 0 ? { command } : {},
629
+ ...(remembered ? { providerMetadata: remembered } : {}),
491
630
  });
492
631
  }
493
632
  continue;
@@ -506,9 +645,11 @@ export function parseRequest(body: unknown): OcxParsedRequest {
506
645
  // history stays complete (otherwise the model re-issues tool_search forever).
507
646
  const call = item as { id?: string; call_id?: string; arguments?: unknown };
508
647
  const callId = call.call_id ?? call.id ?? "";
648
+ const remembered = callId ? replayThoughtSignatureMetadata(callId, replayCacheScope) : undefined;
509
649
  assistantHolderWithReasoning().content.push({
510
650
  type: "toolCall", id: callId, name: "tool_search",
511
651
  arguments: isObj(call.arguments) ? call.arguments : {},
652
+ ...(remembered ? { providerMetadata: remembered } : {}),
512
653
  });
513
654
  continue;
514
655
  }
@@ -545,8 +686,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
545
686
  }
546
687
 
547
688
  if (effectiveType === "function_call_output") {
548
- pendingReasoning.length = 0;
549
689
  const output = item as { call_id: string; output?: string | unknown[] };
690
+ attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
691
+ pendingReasoning.length = 0;
550
692
  const toolInfo = findToolById(messages, output.call_id);
551
693
  messages.push({
552
694
  role: "toolResult", toolCallId: output.call_id,
@@ -558,8 +700,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
558
700
  }
559
701
 
560
702
  if (effectiveType === "custom_tool_call_output") {
561
- pendingReasoning.length = 0;
562
703
  const output = item as { call_id: string; output: string | unknown[] };
704
+ attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
705
+ pendingReasoning.length = 0;
563
706
  const toolInfo = findToolById(messages, output.call_id);
564
707
  messages.push({
565
708
  role: "toolResult", toolCallId: output.call_id,
@@ -572,10 +715,22 @@ export function parseRequest(body: unknown): OcxParsedRequest {
572
715
  }
573
716
  }
574
717
  }
718
+ if (data.previous_response_id && continuationConversationMessageIndex === undefined) {
719
+ continuationConversationMessageIndex = messages.length;
720
+ }
575
721
 
576
722
  const declaredTools = buildTools(data.tools as unknown[] | undefined) ?? [];
577
723
  const loadedTools = buildTools(loadedToolSpecs) ?? [];
578
724
  const loadedToolNames = new Set(loadedTools.map(t => namespacedToolName(t.namespace, t.name)));
725
+ const wireOwners = new Map<string, OcxTool>();
726
+ for (const tool of [...declaredTools, ...loadedTools]) {
727
+ const wireName = namespacedToolName(tool.namespace, tool.name);
728
+ const previous = wireOwners.get(wireName);
729
+ if (previous && (previous.namespace !== tool.namespace || previous.name !== tool.name || previous.freeform !== tool.freeform || previous.toolSearch !== tool.toolSearch)) {
730
+ throw new Error(`ambiguous tool catalog: multiple logical tools map to wire name ${wireName}`);
731
+ }
732
+ wireOwners.set(wireName, tool);
733
+ }
579
734
  const seenTools = new Set<string>();
580
735
  const mergedTools = [...declaredTools, ...loadedTools]
581
736
  .filter(t => {
@@ -601,6 +756,14 @@ export function parseRequest(body: unknown): OcxParsedRequest {
601
756
  options.stopSequences = typeof data.stop === "string" ? [data.stop] : data.stop;
602
757
  }
603
758
  const tc = mapToolChoice(data.tool_choice);
759
+ if (tc && typeof tc === "object") {
760
+ const selectors = "allowedTools" in tc ? tc.allowedTools : [tc.name];
761
+ for (const selector of selectors) {
762
+ if (toolChoiceCandidates(mergedTools, selector).length > 1) {
763
+ throw new Error(`ambiguous tool_choice name: ${selector}`);
764
+ }
765
+ }
766
+ }
604
767
  if (tc !== undefined) options.toolChoice = tc;
605
768
  if (data.parallel_tool_calls !== undefined) options.parallelToolCalls = data.parallel_tool_calls;
606
769
  // Upstream codex-rs converts "ultra" to "max" at the inference boundary (core/src/client.rs
@@ -626,9 +789,12 @@ export function parseRequest(body: unknown): OcxParsedRequest {
626
789
  ...(data.tools as unknown[] ?? []),
627
790
  ...loadedToolSpecs,
628
791
  ]);
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);
792
+ // Capture structured-output mode (Responses `text.format`): the format object rides
793
+ // options.textFormat for adapters whose wire has an equivalent (openai-chat response_format),
794
+ // while the `_structuredOutput` flag keeps the web-search sidecar rendering its tool_result
795
+ // as JSON rather than prose that could corrupt the model's schema-constrained answer.
796
+ const textFormat = parseTextFormat(data.text);
797
+ if (textFormat) options.textFormat = textFormat;
632
798
 
633
799
  return {
634
800
  modelId: data.model,
@@ -638,19 +804,35 @@ export function parseRequest(body: unknown): OcxParsedRequest {
638
804
  options,
639
805
  _rawBody: body,
640
806
  ...(replayedInputPrefixLength > 0 ? { _replayPrefixLen: replayedInputPrefixLength } : {}),
807
+ ...(continuationConversationMessageIndex !== undefined
808
+ ? { _continuationConversationMessageIndex: continuationConversationMessageIndex }
809
+ : {}),
641
810
  ...(webSearch ? { _webSearch: webSearch } : {}),
642
811
  ...(imageGen ? { _imageGeneration: imageGen } : {}),
643
- ...(structuredOutput ? { _structuredOutput: true } : {}),
812
+ ...(textFormat ? { _structuredOutput: true } : {}),
644
813
  ...(compactionRequest ? { _compactionRequest: true } : {}),
645
814
  ...(contextCompactionBoundary ? { _contextCompactionBoundary: true } : {}),
646
815
  };
647
816
  }
648
817
 
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;
818
+ /**
819
+ * The Responses `text.format` object when it requests structured output (json_schema or
820
+ * json_object), undefined otherwise. Acceptance is identical to the boolean detector this
821
+ * replaces; unknown or malformed formats are ignored, never rejected, so the native
822
+ * passthrough keeps forwarding whatever the caller sent via `_rawBody`.
823
+ */
824
+ function parseTextFormat(text: unknown): OcxRequestOptions["textFormat"] {
825
+ if (!isObj(text)) return undefined;
652
826
  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";
827
+ if (!isObj(format)) return undefined;
828
+ const f = format as { type?: unknown; name?: unknown; description?: unknown; schema?: unknown; strict?: unknown };
829
+ if (f.type === "json_object") return { type: "json_object" };
830
+ if (f.type !== "json_schema") return undefined;
831
+ return {
832
+ type: "json_schema",
833
+ ...(typeof f.name === "string" ? { name: f.name } : {}),
834
+ ...(typeof f.description === "string" ? { description: f.description } : {}),
835
+ ...(isObj(f.schema) ? { schema: f.schema as Record<string, unknown> } : {}),
836
+ ...(typeof f.strict === "boolean" ? { strict: f.strict } : {}),
837
+ };
656
838
  }
@@ -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
  }