@iislee/opencodex 2.11.0 → 2.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -0,0 +1,364 @@
1
+ /**
2
+ * Server-side thought-signature replay store (issue #1735 follow-up).
3
+ *
4
+ * Gemini issues a thoughtSignature on the function-call part of a response and requires it
5
+ * back when the same call is replayed in a later request. The Responses wire carries the
6
+ * signature in extra_content.google.thought_signature, and a conforming client echoes it on
7
+ * the replay. Real clients (codex-rs 0.144.x, Codex desktop) do NOT echo extra_content:
8
+ * they replay history as bare function_call / custom_tool_call items keyed by call_id.
9
+ * Without the signature Gemini rejects the replayed part with
10
+ * "Function call is missing a thought_signature in functionCall parts".
11
+ *
12
+ * This module is the proxy-side fallback: remember the signature we handed out and re-attach
13
+ * it on replay even when the client never echoes it. Values stay opaque (never parsed or
14
+ * re-encoded) and are bounded like the wire metadata.
15
+ *
16
+ * SCOPE: a client-visible `call_id` is NOT unique across conversations, accounts, providers
17
+ * or models. Keying on it alone let one thread's signature overwrite another's, and let a
18
+ * lookup hand a signature from a different account's turn to the current one. The key is the
19
+ * same identity the in-process reasoning cache already uses — thread plus exact provider
20
+ * destination, adapter, model and credential — so a signature can only ever be replayed into
21
+ * the turn that produced it.
22
+ */
23
+ import { chmodSync, readFileSync, writeFileSync } from "node:fs";
24
+ import { randomBytes } from "node:crypto";
25
+ import { join } from "node:path";
26
+ import { atomicWriteFileAsync, getConfigDir } from "../config";
27
+ import type { OcxProviderOpaqueToolCallMetadata, OcxReasoningReplayScopeRef } from "../types";
28
+ import { isCarryableSignature, responsesExtraContentFromProviderMetadata } from "./provider-opaque-metadata";
29
+
30
+ const STORE_FILE_NAME = "thought-signature-replay.json";
31
+ const SALT_FILE_NAME = "thought-signature-replay.salt";
32
+ /**
33
+ * Bumped whenever `keyFor` changes shape. v3 added the durable destination identity; v4
34
+ * added the salted durable credential identity (#1926), so a v3 file's keys can never
35
+ * match and are dropped on load instead of aging out invisibly. v3 rows carried no
36
+ * credential information, so they are not upgradable — the next Gemini turn re-accumulates
37
+ * its signatures (bounded, best-effort loss identical to the pre-store status quo).
38
+ */
39
+ const STORE_VERSION = 4;
40
+
41
+ /** Bound on remembered entries; real signatures are a few hundred bytes, so this stays small. */
42
+ const MAX_ENTRIES = 16_384;
43
+ /**
44
+ * Total bytes of remembered signature material.
45
+ *
46
+ * An entry count alone is not a memory bound: a single signature may be 64KiB, so 16,384
47
+ * entries is a ~1GiB ceiling. This is the bound that actually holds.
48
+ */
49
+ const MAX_TOTAL_BYTES = 32 * 1024 * 1024;
50
+ /** A signature is needed for the immediate next turn; a long TTL also covers resumed threads. */
51
+ const TTL_MS = 7 * 24 * 60 * 60 * 1000;
52
+
53
+ type StoredEntry = { sig: string; savedAt: number };
54
+
55
+ /** Outcome of a remember attempt. `conflict` is a real signal, not a no-op. */
56
+ export type ThoughtSignatureRememberResult =
57
+ | "stored"
58
+ | "already-equal"
59
+ | "conflict"
60
+ | "unscoped"
61
+ | "ignored";
62
+
63
+ let entries = new Map<string, StoredEntry>();
64
+ let totalBytes = 0;
65
+ let loaded = false;
66
+ let persistChain: Promise<void> = Promise.resolve();
67
+
68
+ function storePath(): string {
69
+ return join(getConfigDir(), STORE_FILE_NAME);
70
+ }
71
+
72
+ function saltPath(): string {
73
+ return join(getConfigDir(), SALT_FILE_NAME);
74
+ }
75
+
76
+ let cachedSalt: Buffer | undefined;
77
+ let saltLoaded = false;
78
+
79
+ /**
80
+ * Installation-local salt for the durable credential identity (#1926). Created once and
81
+ * persisted beside the store; losing it invalidates every stored key (the entries then
82
+ * never match and age out), which is safe — signatures re-accumulate per turn.
83
+ */
84
+ export function thoughtSignatureReplaySalt(): Buffer | undefined {
85
+ if (saltLoaded) return cachedSalt;
86
+ saltLoaded = true;
87
+ try {
88
+ const raw = readFileSync(saltPath());
89
+ if (raw.length >= 16) {
90
+ // Re-assert owner-only permissions on every load: a pre-existing file may have
91
+ // been created before this guard or loosened by external tooling.
92
+ try { chmodSync(saltPath(), 0o600); } catch { /* best effort on exotic filesystems */ }
93
+ cachedSalt = raw;
94
+ return cachedSalt;
95
+ }
96
+ } catch {
97
+ // fall through to mint
98
+ }
99
+ try {
100
+ const minted = randomBytes(32);
101
+ writeFileSync(saltPath(), minted, { mode: 0o600 });
102
+ cachedSalt = minted;
103
+ } catch {
104
+ // Unwritable config dir: no durable credential identity this process; the durable
105
+ // store fails closed (keyFor returns undefined) rather than keying under a shared id.
106
+ cachedSalt = undefined;
107
+ }
108
+ return cachedSalt;
109
+ }
110
+
111
+ function nonEmpty(value: unknown): value is string {
112
+ return typeof value === "string" && value.trim().length > 0;
113
+ }
114
+
115
+ /**
116
+ * Durable key for one call, or `undefined` when the scope is incomplete.
117
+ *
118
+ * Incomplete scope means "do not remember" rather than "remember globally": a partially
119
+ * identified entry is exactly the cross-thread collision this store exists to prevent.
120
+ * The reasoning cache's identities are process-local HMACs, so this key deliberately uses
121
+ * only the stable, non-secret fields that survive a restart.
122
+ */
123
+ function keyFor(callId: string, scope: OcxReasoningReplayScopeRef | undefined): string | undefined {
124
+ const identity = scope?.current;
125
+ if (
126
+ !nonEmpty(callId)
127
+ || !nonEmpty(scope?.clientThreadId)
128
+ || !nonEmpty(identity?.providerName)
129
+ || !nonEmpty(identity?.adapterName)
130
+ || !nonEmpty(identity?.modelId)
131
+ // v4 (#1926): a missing durable credential identity means we cannot isolate this
132
+ // entry per credential across restarts. Refusing the key is the fail-closed choice —
133
+ // "credential:unknown" would let two different credentials share one durable slot.
134
+ || !nonEmpty(identity?.credentialDurableIdentity)
135
+ ) return undefined;
136
+ return JSON.stringify([
137
+ scope.clientThreadId,
138
+ identity.providerName,
139
+ // Destination, unlike the credential identity, has a restart-stable form: it is a
140
+ // configured endpoint rather than a secret, so a plain digest works where the
141
+ // reasoning cache's randomBytes-keyed HMAC cannot. Without it, one provider NAME
142
+ // serving two endpoints shares signatures across both.
143
+ identity.providerDestinationDurableIdentity ?? "destination:unknown",
144
+ identity.credentialDurableIdentity,
145
+ identity.adapterName,
146
+ identity.modelId,
147
+ callId,
148
+ ]);
149
+ }
150
+
151
+ function load(): void {
152
+ if (loaded) return;
153
+ loaded = true;
154
+ let raw: string;
155
+ try {
156
+ raw = readFileSync(storePath(), "utf8");
157
+ } catch {
158
+ return; // First run or unreadable file: start empty.
159
+ }
160
+ try {
161
+ const parsed: unknown = JSON.parse(raw);
162
+ if (typeof parsed !== "object" || parsed === null || !Array.isArray((parsed as { entries?: unknown }).entries)) {
163
+ return;
164
+ }
165
+ // The version was written but never read, so a key-shape change could not be
166
+ // announced — old entries simply went dead and aged out on TTL, which is silent and
167
+ // indistinguishable from a store that is not working. Reading it makes a shape change
168
+ // an explicit drop: entries keyed by an older scheme are discarded on load rather than
169
+ // lingering as permanent misses.
170
+ if ((parsed as { version?: unknown }).version !== STORE_VERSION) return;
171
+ const nowMs = Date.now();
172
+ for (const entry of (parsed as { entries: unknown[] }).entries) {
173
+ if (typeof entry !== "object" || entry === null) continue;
174
+ const { key, sig, savedAt } = entry as { key?: unknown; sig?: unknown; savedAt?: unknown };
175
+ if (typeof key !== "string" || typeof sig !== "string" || typeof savedAt !== "number") continue;
176
+ if (savedAt <= nowMs - TTL_MS) continue;
177
+ if (!isCarryableSignature(sig)) continue;
178
+ entries.set(key, { sig, savedAt });
179
+ totalBytes += sig.length;
180
+ }
181
+ } catch {
182
+ // Corrupt store: ignore it; a later remember() rewrites a clean snapshot.
183
+ }
184
+ // A loaded snapshot can already exceed the bounds if they were lowered, so enforce them
185
+ // here rather than waiting for the next write.
186
+ prune(Date.now());
187
+ }
188
+
189
+ function prune(nowMs: number): void {
190
+ for (const [key, entry] of entries) {
191
+ if (nowMs - entry.savedAt > TTL_MS) {
192
+ entries.delete(key);
193
+ totalBytes -= entry.sig.length;
194
+ }
195
+ }
196
+ if (entries.size <= MAX_ENTRIES && totalBytes <= MAX_TOTAL_BYTES) return;
197
+ const sorted = [...entries.entries()].sort((a, b) => a[1].savedAt - b[1].savedAt);
198
+ for (const [key, entry] of sorted) {
199
+ if (entries.size <= MAX_ENTRIES && totalBytes <= MAX_TOTAL_BYTES) break;
200
+ entries.delete(key);
201
+ totalBytes -= entry.sig.length;
202
+ }
203
+ }
204
+
205
+ function persist(): Promise<void> {
206
+ persistChain = persistChain
207
+ .then(async () => {
208
+ const snapshot = JSON.stringify({
209
+ version: STORE_VERSION,
210
+ entries: [...entries].map(([key, entry]) => ({ key, sig: entry.sig, savedAt: entry.savedAt })),
211
+ });
212
+ await atomicWriteFileAsync(storePath(), snapshot);
213
+ })
214
+ .catch(() => {
215
+ // Best-effort persistence: the in-memory store still serves the running process.
216
+ });
217
+ return persistChain;
218
+ }
219
+
220
+ /**
221
+ * Record the signature that left the proxy on a function-call response item.
222
+ *
223
+ * Returns the outcome so a caller can await durability before exposing the item, and so a
224
+ * genuine conflict is observable instead of silently overwriting. A different signature under
225
+ * the SAME complete key means two different upstream turns claimed one identity: that is a
226
+ * corruption signal, and keeping the first value is the fail-closed choice.
227
+ */
228
+ export function rememberThoughtSignatureForReplay(
229
+ callId: string,
230
+ signature: string,
231
+ scope: OcxReasoningReplayScopeRef | undefined,
232
+ ): { result: ThoughtSignatureRememberResult; durable: Promise<void> } {
233
+ if (!callId || !isCarryableSignature(signature)) {
234
+ return { result: "ignored", durable: Promise.resolve() };
235
+ }
236
+ const key = keyFor(callId, scope);
237
+ if (key === undefined) return { result: "unscoped", durable: Promise.resolve() };
238
+ load();
239
+ const existing = entries.get(key);
240
+ if (existing) {
241
+ if (existing.sig === signature) return { result: "already-equal", durable: Promise.resolve() };
242
+ return { result: "conflict", durable: Promise.resolve() };
243
+ }
244
+ entries.set(key, { sig: signature, savedAt: Date.now() });
245
+ totalBytes += signature.length;
246
+ prune(Date.now());
247
+ return { result: "stored", durable: persist() };
248
+ }
249
+
250
+ /**
251
+ * Serialize provider metadata onto an outbound Responses function_call item AND remember the
252
+ * signature server-side, so a client that replays the call without echoing extra_content can
253
+ * still be served from the store.
254
+ */
255
+ export function rememberAndSerializeExtraContent(
256
+ callId: string,
257
+ metadata: OcxProviderOpaqueToolCallMetadata | undefined,
258
+ scope: OcxReasoningReplayScopeRef | undefined,
259
+ ): {
260
+ extra?: { extra_content: { google: { thought_signature: string } } };
261
+ durable: Promise<void>;
262
+ } {
263
+ const extra = responsesExtraContentFromProviderMetadata(metadata);
264
+ if (!extra) return { durable: Promise.resolve() };
265
+ const { durable } = rememberThoughtSignatureForReplay(
266
+ callId,
267
+ extra.extra_content.google.thought_signature,
268
+ scope,
269
+ );
270
+ return { extra, durable };
271
+ }
272
+
273
+ /**
274
+ * Remember the signature without serializing it onto the item. Used for freeform tools, whose
275
+ * Responses items are custom_tool_call blocks that cannot carry extra_content — the signature
276
+ * still must be stored so the replayed call (which comes back as custom_tool_call and never
277
+ * echoes metadata) can be re-signed server-side.
278
+ */
279
+ export function rememberExtraContentForReplay(
280
+ callId: string,
281
+ metadata: OcxProviderOpaqueToolCallMetadata | undefined,
282
+ scope: OcxReasoningReplayScopeRef | undefined,
283
+ ): Promise<void> {
284
+ const extra = responsesExtraContentFromProviderMetadata(metadata);
285
+ if (!extra) return Promise.resolve();
286
+ return rememberThoughtSignatureForReplay(
287
+ callId,
288
+ extra.extra_content.google.thought_signature,
289
+ scope,
290
+ ).durable;
291
+ }
292
+
293
+ /** Look up a signature previously handed out for this call in THIS scope, if still fresh. */
294
+ export function lookupReplayThoughtSignature(
295
+ callId: string,
296
+ scope: OcxReasoningReplayScopeRef | undefined,
297
+ ): string | undefined {
298
+ const key = keyFor(callId, scope);
299
+ if (key === undefined) return undefined;
300
+ load();
301
+ const entry = entries.get(key);
302
+ if (!entry) return undefined;
303
+ if (Date.now() - entry.savedAt > TTL_MS) {
304
+ entries.delete(key);
305
+ totalBytes -= entry.sig.length;
306
+ return undefined;
307
+ }
308
+ return entry.sig;
309
+ }
310
+
311
+ /** Drop a remembered signature for a specific callId and scope (e.g. when upstream rejects it). */
312
+ export function forgetThoughtSignatureForReplay(
313
+ callId: string,
314
+ scope: OcxReasoningReplayScopeRef | undefined,
315
+ ): boolean {
316
+ const key = keyFor(callId, scope);
317
+ if (key === undefined) return false;
318
+ load();
319
+ const entry = entries.get(key);
320
+ if (!entry) return false;
321
+ entries.delete(key);
322
+ totalBytes -= entry.sig.length;
323
+ prune(Date.now());
324
+ void persist();
325
+ return true;
326
+ }
327
+
328
+ /** Test seams: clear in-memory state and the loaded flag without touching the file. */
329
+ export function resetThoughtSignatureReplayForTests(): void {
330
+ entries = new Map();
331
+ totalBytes = 0;
332
+ loaded = false;
333
+ persistChain = Promise.resolve();
334
+ cachedSalt = undefined;
335
+ saltLoaded = false;
336
+ }
337
+
338
+ export function thoughtSignatureReplayCountForTests(): number {
339
+ return entries.size;
340
+ }
341
+
342
+ /** Test seam: resolve after the queued snapshot write settles. */
343
+ export function flushThoughtSignatureReplayForTests(): Promise<void> {
344
+ return persistChain;
345
+ }
346
+
347
+ /**
348
+ * Bounded commit barrier (#1926 gap 2). All durable writes serialize onto
349
+ * `persistChain`, so awaiting it (with a cap) before a turn's terminal frame becomes
350
+ * externally visible bounds the restart window in which a handed-out signature could
351
+ * be lost. Bounded BEST EFFORT: on timeout the turn proceeds — availability wins, and
352
+ * the miss cost is one turn's re-accumulation (the pre-store status quo). The
353
+ * in-memory map is updated synchronously at remember() time, so within one process
354
+ * lifetime replay never races this barrier at all.
355
+ */
356
+ export function awaitThoughtSignatureDurability(capMs = 250): Promise<void> {
357
+ let timer: ReturnType<typeof setTimeout> | undefined;
358
+ const cap = new Promise<void>(resolve => {
359
+ timer = setTimeout(resolve, capMs);
360
+ });
361
+ return Promise.race([persistChain, cap]).then(() => {
362
+ if (timer !== undefined) clearTimeout(timer);
363
+ });
364
+ }
@@ -0,0 +1,301 @@
1
+ export const TOOL_SEARCH_FUNCTION_NAME = "tool_search";
2
+ export const TOOL_SEARCH_DEFAULT_DESCRIPTION = "Search for additional tools to load for the next turn.";
3
+ const TOOL_SEARCH_WIRE_ALIAS_PREFIX = "opencodex_tool_search";
4
+
5
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
6
+ return !!value && typeof value === "object" && !Array.isArray(value);
7
+ }
8
+
9
+ export function toolSearchDescription(tool: unknown): string {
10
+ return isPlainObject(tool) && typeof tool.description === "string"
11
+ ? tool.description
12
+ : TOOL_SEARCH_DEFAULT_DESCRIPTION;
13
+ }
14
+
15
+ export function toolSearchParameters(tool: unknown): Record<string, unknown> {
16
+ if (isPlainObject(tool) && isPlainObject(tool.parameters)) return tool.parameters;
17
+ // Fresh per parse/build: downstream normalizers are allowed to clone or extend schemas, and a
18
+ // shared mutable default would couple otherwise unrelated requests.
19
+ return {
20
+ type: "object",
21
+ properties: {
22
+ query: { type: "string", description: "Search query for tools to load." },
23
+ limit: { type: "number", description: "Maximum number of tools to return." },
24
+ },
25
+ required: ["query"],
26
+ };
27
+ }
28
+
29
+ function collectToolDeclarationNames(tools: unknown[], names: Set<string>, namespace?: string): void {
30
+ for (const tool of tools) {
31
+ if (!isPlainObject(tool) || tool.type === "tool_search") continue;
32
+ if (tool.type === "function" && isPlainObject(tool.function) && typeof tool.function.name === "string") {
33
+ names.add(tool.function.name);
34
+ }
35
+ if (typeof tool.name === "string") {
36
+ names.add(tool.name);
37
+ if (namespace) names.add(`${namespace}__${tool.name}`);
38
+ }
39
+ if (tool.type === "namespace" && Array.isArray(tool.tools)) {
40
+ collectToolDeclarationNames(tool.tools, names, typeof tool.name === "string" ? tool.name : undefined);
41
+ }
42
+ }
43
+ }
44
+
45
+ function declaredToolNames(body: Record<string, unknown>): Set<string> {
46
+ const names = new Set<string>();
47
+ if (Array.isArray(body.tools)) collectToolDeclarationNames(body.tools, names);
48
+ if (Array.isArray(body.input)) {
49
+ for (const item of body.input) {
50
+ if (isPlainObject(item) && item.type === "additional_tools" && Array.isArray(item.tools)) {
51
+ collectToolDeclarationNames(item.tools, names);
52
+ }
53
+ }
54
+ }
55
+ return names;
56
+ }
57
+
58
+ function hasToolSearchDeclaration(tools: unknown[]): boolean {
59
+ return tools.some(tool => isPlainObject(tool) && tool.type === "tool_search");
60
+ }
61
+
62
+ function chooseToolSearchWireName(usedNames: ReadonlySet<string>): string {
63
+ if (!usedNames.has(TOOL_SEARCH_FUNCTION_NAME)) return TOOL_SEARCH_FUNCTION_NAME;
64
+ if (!usedNames.has(TOOL_SEARCH_WIRE_ALIAS_PREFIX)) return TOOL_SEARCH_WIRE_ALIAS_PREFIX;
65
+ for (let suffix = 2; ; suffix++) {
66
+ const candidate = `${TOOL_SEARCH_WIRE_ALIAS_PREFIX}_${suffix}`;
67
+ if (!usedNames.has(candidate)) return candidate;
68
+ }
69
+ }
70
+
71
+ function rewriteToolList(tools: unknown[], wireName: string): { tools: unknown[]; changed: boolean } {
72
+ let changed = false;
73
+ const rewritten = tools.map(tool => {
74
+ if (!isPlainObject(tool) || tool.type !== "tool_search") return tool;
75
+ const {
76
+ execution: _execution,
77
+ defer_loading: _deferLoading,
78
+ ...rest
79
+ } = tool;
80
+ changed = true;
81
+ return {
82
+ ...rest,
83
+ type: "function",
84
+ name: wireName,
85
+ description: toolSearchDescription(tool),
86
+ parameters: toolSearchParameters(tool),
87
+ };
88
+ });
89
+ return changed ? { tools: rewritten, changed: true } : { tools, changed: false };
90
+ }
91
+
92
+ function rewriteToolChoice(choice: unknown, wireName: string): unknown {
93
+ if (!isPlainObject(choice)) return choice;
94
+ if (choice.type === "tool_search") {
95
+ return { type: "function", name: wireName };
96
+ }
97
+ if (choice.type !== "allowed_tools" || !Array.isArray(choice.tools)) return choice;
98
+ let changed = false;
99
+ const tools = choice.tools.map(tool => {
100
+ if (!isPlainObject(tool) || tool.type !== "tool_search") return tool;
101
+ changed = true;
102
+ return { type: "function", name: wireName };
103
+ });
104
+ return changed ? { ...choice, tools } : choice;
105
+ }
106
+
107
+ function toolChoiceAllowsPrivateSearch(choice: unknown): boolean {
108
+ if (choice === undefined || choice === null || choice === "auto" || choice === "required") return true;
109
+ if (choice === "none") return false;
110
+ if (!isPlainObject(choice)) return true;
111
+ if (choice.type === "tool_search") return true;
112
+ if (choice.type === "allowed_tools" && Array.isArray(choice.tools)) {
113
+ return choice.tools.some(tool => isPlainObject(tool) && tool.type === "tool_search");
114
+ }
115
+ // A forced ordinary function named `tool_search` is distinct from the private tool kind.
116
+ return false;
117
+ }
118
+
119
+ function upstreamToolSearchItemId(id: unknown): unknown {
120
+ if (typeof id !== "string") return id;
121
+ return id.startsWith("tsc_") ? `fc_${id.slice(4)}` : id;
122
+ }
123
+
124
+ function toolSearchArgumentsText(value: unknown): string {
125
+ if (typeof value === "string") return value;
126
+ return JSON.stringify(isPlainObject(value) ? value : {});
127
+ }
128
+
129
+ function toolSearchOutputText(value: Record<string, unknown>): string {
130
+ const payload: Record<string, unknown> = {
131
+ tools: Array.isArray(value.tools) ? value.tools : [],
132
+ };
133
+ if (typeof value.status === "string") payload.status = value.status;
134
+ return JSON.stringify(payload);
135
+ }
136
+
137
+ function rewriteHistoryItem(item: Record<string, unknown>, wireName: string): Record<string, unknown> {
138
+ if (item.type === "tool_search_call") {
139
+ const {
140
+ execution: _execution,
141
+ arguments: argumentsValue,
142
+ id,
143
+ ...rest
144
+ } = item;
145
+ return {
146
+ ...rest,
147
+ type: "function_call",
148
+ ...(id === undefined ? {} : { id: upstreamToolSearchItemId(id) }),
149
+ name: wireName,
150
+ arguments: toolSearchArgumentsText(argumentsValue),
151
+ };
152
+ }
153
+ if (item.type === "tool_search_output") {
154
+ const {
155
+ execution: _execution,
156
+ id: _id,
157
+ tools: _tools,
158
+ status: _status,
159
+ ...rest
160
+ } = item;
161
+ return {
162
+ ...rest,
163
+ type: "function_call_output",
164
+ output: toolSearchOutputText(item),
165
+ };
166
+ }
167
+ return item;
168
+ }
169
+
170
+ /**
171
+ * Third-party Responses gateways generally implement the public function-tool schema, not Codex's
172
+ * private client-executed `tool_search` declaration. Lower only request catalogs sent to a
173
+ * noncanonical upstream; the caller-facing response is restored separately.
174
+ */
175
+ export function rewriteRoutedToolSearchForUpstream(body: unknown): {
176
+ body: unknown;
177
+ names: Set<string>;
178
+ } {
179
+ const names = new Set<string>();
180
+ if (!isPlainObject(body)) return { body, names };
181
+
182
+ const topLevelSearch = Array.isArray(body.tools) && hasToolSearchDeclaration(body.tools);
183
+ const inputItems = Array.isArray(body.input) ? body.input : [];
184
+ const additionalSearch = inputItems.some(item =>
185
+ isPlainObject(item)
186
+ && item.type === "additional_tools"
187
+ && Array.isArray(item.tools)
188
+ && hasToolSearchDeclaration(item.tools));
189
+ const historySearch = inputItems.some(item =>
190
+ isPlainObject(item)
191
+ && (item.type === "tool_search_call" || item.type === "tool_search_output"));
192
+ if (!topLevelSearch && !additionalSearch && !historySearch) return { body, names };
193
+
194
+ const wireName = chooseToolSearchWireName(declaredToolNames(body));
195
+ const declarationChanged = topLevelSearch || additionalSearch;
196
+
197
+ let tools = body.tools;
198
+ if (Array.isArray(tools)) {
199
+ const result = rewriteToolList(tools, wireName);
200
+ tools = result.tools;
201
+ }
202
+
203
+ let input = body.input;
204
+ let historyLowered = false;
205
+ if (Array.isArray(input)) {
206
+ input = input.map(item => {
207
+ if (!isPlainObject(item)) return item;
208
+ if (item.type === "additional_tools" && Array.isArray(item.tools)) {
209
+ const result = rewriteToolList(item.tools, wireName);
210
+ return result.changed ? { ...item, tools: result.tools } : item;
211
+ }
212
+ const rewritten = rewriteHistoryItem(item, wireName);
213
+ if (rewritten !== item) historyLowered = true;
214
+ return rewritten;
215
+ });
216
+ }
217
+
218
+ // A turn can replay `tool_search_call` history WITHOUT re-declaring the tool — Codex normally
219
+ // sends the declaration, but a history-only body is legal. The history is lowered to
220
+ // `function_call` either way, so restoration has to be armed on that too: leaving `names`
221
+ // empty there would hand the client a public `function_call` for what it issued as a private
222
+ // search call, and the round trip would silently stop matching.
223
+ if ((declarationChanged || historyLowered) && toolChoiceAllowsPrivateSearch(body.tool_choice)) {
224
+ names.add(wireName);
225
+ }
226
+ const toolChoice = declarationChanged ? rewriteToolChoice(body.tool_choice, wireName) : body.tool_choice;
227
+ return {
228
+ body: {
229
+ ...body,
230
+ ...(tools !== body.tools ? { tools } : {}),
231
+ ...(input !== body.input ? { input } : {}),
232
+ ...(toolChoice !== body.tool_choice ? { tool_choice: toolChoice } : {}),
233
+ },
234
+ names,
235
+ };
236
+ }
237
+
238
+ export function toolSearchItemId(id: unknown): unknown {
239
+ if (typeof id !== "string") return id;
240
+ return id.startsWith("fc_") ? `tsc_${id.slice(3)}` : id;
241
+ }
242
+
243
+ function toolSearchArguments(value: unknown): Record<string, unknown> {
244
+ if (isPlainObject(value)) return value;
245
+ if (typeof value !== "string" || value.length === 0) return {};
246
+ try {
247
+ const parsed: unknown = JSON.parse(value);
248
+ return isPlainObject(parsed) ? parsed : {};
249
+ } catch {
250
+ return {};
251
+ }
252
+ }
253
+
254
+ export function restoreRoutedToolSearchCalls(
255
+ value: unknown,
256
+ names: ReadonlySet<string>,
257
+ ): { value: unknown; changed: boolean } {
258
+ if (Array.isArray(value)) {
259
+ let changed = false;
260
+ const restored = value.map(entry => {
261
+ const result = restoreRoutedToolSearchCalls(entry, names);
262
+ changed ||= result.changed;
263
+ return result.value;
264
+ });
265
+ return changed ? { value: restored, changed: true } : { value, changed: false };
266
+ }
267
+ if (!isPlainObject(value)) return { value, changed: false };
268
+
269
+ let changed = false;
270
+ const restored: Record<string, unknown> = {};
271
+ for (const [key, entry] of Object.entries(value)) {
272
+ const result = restoreRoutedToolSearchCalls(entry, names);
273
+ restored[key] = result.value;
274
+ changed ||= result.changed;
275
+ }
276
+
277
+ if (value.type === "function_call" && typeof value.name === "string" && names.has(value.name)) {
278
+ restored.type = "tool_search_call";
279
+ restored.id = toolSearchItemId(value.id);
280
+ restored.execution = "client";
281
+ restored.arguments = toolSearchArguments(value.arguments);
282
+ delete restored.name;
283
+ changed = true;
284
+ }
285
+ return changed ? { value: restored, changed: true } : { value, changed: false };
286
+ }
287
+
288
+ export function restoreRoutedToolSearchCallsInJson(
289
+ text: string,
290
+ names: ReadonlySet<string>,
291
+ ): string {
292
+ if (names.size === 0) return text;
293
+ let payload: unknown;
294
+ try {
295
+ payload = JSON.parse(text);
296
+ } catch {
297
+ return text;
298
+ }
299
+ const restored = restoreRoutedToolSearchCalls(payload, names);
300
+ return restored.changed ? JSON.stringify(restored.value) : text;
301
+ }