@remodex/rmx 1.0.2

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 (588) hide show
  1. package/AGENTS_INSTALL.md +91 -0
  2. package/LICENSE +21 -0
  3. package/README.md +242 -0
  4. package/assets/architecture.png +0 -0
  5. package/assets/banner.png +0 -0
  6. package/assets/claude-code-models.gif +0 -0
  7. package/assets/codex-app-picker.png +0 -0
  8. package/bin/ocx.mjs +584 -0
  9. package/bin/package-main.mjs +9 -0
  10. package/gui/dist/assets/index-CZqebSPQ.css +1 -0
  11. package/gui/dist/assets/index-CkETtt7P.js +71 -0
  12. package/gui/dist/favicon.png +0 -0
  13. package/gui/dist/fonts/google-sans-cyrillic.woff2 +0 -0
  14. package/gui/dist/fonts/google-sans-latin.woff2 +0 -0
  15. package/gui/dist/icons.svg +24 -0
  16. package/gui/dist/index.html +25 -0
  17. package/gui/dist/logo.png +0 -0
  18. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  19. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  20. package/gui/dist/provider-icons/claude-color.svg +1 -0
  21. package/gui/dist/provider-icons/cline-color.svg +16 -0
  22. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  23. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  24. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  25. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  26. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  27. package/gui/dist/provider-icons/discord.svg +1 -0
  28. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  29. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  30. package/gui/dist/provider-icons/gemini-color.svg +1 -0
  31. package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
  32. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
  33. package/gui/dist/provider-icons/grok.svg +1 -0
  34. package/gui/dist/provider-icons/groq-color.svg +1 -0
  35. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  36. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  37. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  38. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  39. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  40. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  41. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  42. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  43. package/gui/dist/provider-icons/openai.svg +1 -0
  44. package/gui/dist/provider-icons/opencode.svg +2 -0
  45. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  46. package/gui/dist/provider-icons/pi.svg +21 -0
  47. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  48. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  49. package/gui/dist/provider-icons/telegram.svg +1 -0
  50. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  51. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  52. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  53. package/package.json +118 -0
  54. package/src/AGENTS.md +28 -0
  55. package/src/adapters/anthropic-image-guard.ts +251 -0
  56. package/src/adapters/anthropic-image-normalize.ts +518 -0
  57. package/src/adapters/anthropic.ts +1205 -0
  58. package/src/adapters/azure.ts +36 -0
  59. package/src/adapters/base.ts +83 -0
  60. package/src/adapters/client-fingerprint.ts +59 -0
  61. package/src/adapters/command-code.ts +453 -0
  62. package/src/adapters/cursor/arg-codec.ts +38 -0
  63. package/src/adapters/cursor/arg-normalize.ts +104 -0
  64. package/src/adapters/cursor/cursor-errors.ts +165 -0
  65. package/src/adapters/cursor/discovery.ts +276 -0
  66. package/src/adapters/cursor/effort-map.ts +139 -0
  67. package/src/adapters/cursor/exec-policy.ts +88 -0
  68. package/src/adapters/cursor/framing.ts +250 -0
  69. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  70. package/src/adapters/cursor/kv-store.ts +52 -0
  71. package/src/adapters/cursor/live-models.ts +153 -0
  72. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  73. package/src/adapters/cursor/live-transport.ts +1235 -0
  74. package/src/adapters/cursor/mcp-config.ts +42 -0
  75. package/src/adapters/cursor/mcp-manager.ts +333 -0
  76. package/src/adapters/cursor/message-mapper.ts +49 -0
  77. package/src/adapters/cursor/native-exec-common.ts +59 -0
  78. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  79. package/src/adapters/cursor/native-exec-fs.ts +332 -0
  80. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  81. package/src/adapters/cursor/native-exec-network.ts +43 -0
  82. package/src/adapters/cursor/native-exec-shell.ts +548 -0
  83. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  84. package/src/adapters/cursor/native-exec.ts +604 -0
  85. package/src/adapters/cursor/protobuf-events.ts +735 -0
  86. package/src/adapters/cursor/protobuf-request.ts +719 -0
  87. package/src/adapters/cursor/request-builder.ts +280 -0
  88. package/src/adapters/cursor/thread-continuity.ts +67 -0
  89. package/src/adapters/cursor/tool-definitions.ts +621 -0
  90. package/src/adapters/cursor/transport-retry.ts +132 -0
  91. package/src/adapters/cursor/transport.ts +57 -0
  92. package/src/adapters/cursor/types.ts +59 -0
  93. package/src/adapters/cursor.ts +196 -0
  94. package/src/adapters/google-antigravity-replay.ts +520 -0
  95. package/src/adapters/google-antigravity-wire.ts +140 -0
  96. package/src/adapters/google-errors.ts +85 -0
  97. package/src/adapters/google-http.ts +100 -0
  98. package/src/adapters/google-tool-schema.ts +173 -0
  99. package/src/adapters/google-truncation.ts +24 -0
  100. package/src/adapters/google-wire-compiler.ts +232 -0
  101. package/src/adapters/google.ts +859 -0
  102. package/src/adapters/identity.ts +77 -0
  103. package/src/adapters/image.ts +23 -0
  104. package/src/adapters/kiro-constants.ts +16 -0
  105. package/src/adapters/kiro-errors.ts +208 -0
  106. package/src/adapters/kiro-events.ts +197 -0
  107. package/src/adapters/kiro-images.ts +129 -0
  108. package/src/adapters/kiro-retry.ts +312 -0
  109. package/src/adapters/kiro-thinking.ts +104 -0
  110. package/src/adapters/kiro-tool-fallback.ts +36 -0
  111. package/src/adapters/kiro-tools.ts +224 -0
  112. package/src/adapters/kiro-truncation.ts +33 -0
  113. package/src/adapters/kiro-wire.ts +129 -0
  114. package/src/adapters/kiro.ts +1924 -0
  115. package/src/adapters/mimo-free.ts +263 -0
  116. package/src/adapters/openai-chat.ts +1265 -0
  117. package/src/adapters/openai-responses.ts +1309 -0
  118. package/src/adapters/run-turn-queue.ts +114 -0
  119. package/src/adapters/tool-catalog-nudge.ts +71 -0
  120. package/src/adapters/upstream-http-error.ts +48 -0
  121. package/src/android-remote/assets.ts +218 -0
  122. package/src/android-remote/attachments.ts +168 -0
  123. package/src/android-remote/auth.ts +237 -0
  124. package/src/android-remote/cloudflare-provisioning.ts +409 -0
  125. package/src/android-remote/cloudflare-secret.ts +106 -0
  126. package/src/android-remote/cloudflare-tunnel.ts +488 -0
  127. package/src/android-remote/cloudflared.ts +286 -0
  128. package/src/android-remote/codex-app-server.ts +565 -0
  129. package/src/android-remote/desktop-history-page.ts +936 -0
  130. package/src/android-remote/desktop-ipc.ts +3643 -0
  131. package/src/android-remote/desktop-ownership-store.ts +98 -0
  132. package/src/android-remote/desktop-project-registration.ts +129 -0
  133. package/src/android-remote/desktop-session-stream.ts +1110 -0
  134. package/src/android-remote/desktop-workspace-state.ts +443 -0
  135. package/src/android-remote/file-change-parser.ts +112 -0
  136. package/src/android-remote/gateway.ts +9108 -0
  137. package/src/android-remote/mutation-store.ts +299 -0
  138. package/src/android-remote/projection.ts +1780 -0
  139. package/src/android-remote/queued-turn-store.ts +248 -0
  140. package/src/android-remote/session-command-recovery.ts +1384 -0
  141. package/src/android-remote/store.ts +466 -0
  142. package/src/android-remote/thread-reconciliation.ts +133 -0
  143. package/src/android-remote/thread-source-paths.ts +307 -0
  144. package/src/android-remote/thread-stream.ts +546 -0
  145. package/src/android-remote/turn-activity.ts +235 -0
  146. package/src/android-remote/user-message-identity.ts +94 -0
  147. package/src/bridge.ts +1793 -0
  148. package/src/chat/inbound.ts +295 -0
  149. package/src/chat/outbound.ts +821 -0
  150. package/src/claude/agents-inject.ts +267 -0
  151. package/src/claude/alias.ts +149 -0
  152. package/src/claude/auth-detect.ts +229 -0
  153. package/src/claude/auth-mode-migration.ts +32 -0
  154. package/src/claude/auth-mode.ts +62 -0
  155. package/src/claude/context-windows.ts +189 -0
  156. package/src/claude/desktop-3p-guard.ts +35 -0
  157. package/src/claude/desktop-3p-paths.ts +84 -0
  158. package/src/claude/desktop-3p.ts +601 -0
  159. package/src/claude/desktop-health.ts +26 -0
  160. package/src/claude/desktop-profile.ts +263 -0
  161. package/src/claude/gateway-cache.ts +70 -0
  162. package/src/claude/inbound-debug.ts +163 -0
  163. package/src/claude/inbound.ts +519 -0
  164. package/src/claude/model-info.ts +154 -0
  165. package/src/claude/outbound.ts +898 -0
  166. package/src/cli/access.ts +108 -0
  167. package/src/cli/account-api.ts +296 -0
  168. package/src/cli/account-auth.ts +250 -0
  169. package/src/cli/account-catalog-refresh.ts +14 -0
  170. package/src/cli/account-extended.ts +476 -0
  171. package/src/cli/account-main.ts +317 -0
  172. package/src/cli/account.ts +297 -0
  173. package/src/cli/agent-driven.ts +70 -0
  174. package/src/cli/agent.ts +184 -0
  175. package/src/cli/catalog-prewarm.ts +27 -0
  176. package/src/cli/claude-desktop.ts +211 -0
  177. package/src/cli/claude.ts +302 -0
  178. package/src/cli/codex-shim-autorestore.ts +45 -0
  179. package/src/cli/codex-shim-readiness.ts +69 -0
  180. package/src/cli/combo.ts +124 -0
  181. package/src/cli/config-command.ts +183 -0
  182. package/src/cli/debug.ts +228 -0
  183. package/src/cli/desktop-first-run.ts +25 -0
  184. package/src/cli/doctor.ts +1022 -0
  185. package/src/cli/export-command.ts +201 -0
  186. package/src/cli/help.ts +370 -0
  187. package/src/cli/index.ts +1565 -0
  188. package/src/cli/init.ts +224 -0
  189. package/src/cli/integrations.ts +225 -0
  190. package/src/cli/interactive-confirm.ts +133 -0
  191. package/src/cli/internal-dispatch.ts +35 -0
  192. package/src/cli/launcher-context.ts +77 -0
  193. package/src/cli/models-runtime.ts +224 -0
  194. package/src/cli/models.ts +340 -0
  195. package/src/cli/observe.ts +170 -0
  196. package/src/cli/opencode.ts +587 -0
  197. package/src/cli/provider-runtime.ts +179 -0
  198. package/src/cli/provider.ts +476 -0
  199. package/src/cli/ready.ts +301 -0
  200. package/src/cli/route-policy.ts +92 -0
  201. package/src/cli/runtime-api.ts +328 -0
  202. package/src/cli/star-prompt.ts +211 -0
  203. package/src/cli/status-oauth.ts +78 -0
  204. package/src/cli/status.ts +321 -0
  205. package/src/cli/system-command.ts +196 -0
  206. package/src/cli/system-restart-client.ts +146 -0
  207. package/src/cli/tray-proxy.ts +205 -0
  208. package/src/cli/v2.ts +200 -0
  209. package/src/cli.ts +10 -0
  210. package/src/clients/config-export.ts +1109 -0
  211. package/src/codex/account-id.ts +34 -0
  212. package/src/codex/account-label.ts +34 -0
  213. package/src/codex/account-lifecycle.ts +172 -0
  214. package/src/codex/account-namespace-match.ts +63 -0
  215. package/src/codex/account-namespaces.ts +195 -0
  216. package/src/codex/account-pause.ts +20 -0
  217. package/src/codex/account-priority.ts +83 -0
  218. package/src/codex/account-runtime-state.ts +31 -0
  219. package/src/codex/account-store.ts +517 -0
  220. package/src/codex/account-usability.ts +40 -0
  221. package/src/codex/admission.ts +263 -0
  222. package/src/codex/app-server-processes.ts +799 -0
  223. package/src/codex/auth-api.ts +2098 -0
  224. package/src/codex/auth-collision.ts +107 -0
  225. package/src/codex/auth-context.ts +480 -0
  226. package/src/codex/autostart-health.ts +156 -0
  227. package/src/codex/catalog/account-models.ts +67 -0
  228. package/src/codex/catalog/aggregation.ts +471 -0
  229. package/src/codex/catalog/bundled.ts +533 -0
  230. package/src/codex/catalog/effort.ts +432 -0
  231. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  232. package/src/codex/catalog/kinds.ts +2 -0
  233. package/src/codex/catalog/metadata.ts +287 -0
  234. package/src/codex/catalog/native-models.ts +7 -0
  235. package/src/codex/catalog/parsing.ts +503 -0
  236. package/src/codex/catalog/provider-fetch.ts +2267 -0
  237. package/src/codex/catalog/sync.ts +1606 -0
  238. package/src/codex/catalog-admission.ts +197 -0
  239. package/src/codex/catalog-refresh-status.ts +87 -0
  240. package/src/codex/catalog-write-serialization.ts +242 -0
  241. package/src/codex/catalog.ts +15 -0
  242. package/src/codex/codex-write-lock.ts +384 -0
  243. package/src/codex/convergence-types.ts +593 -0
  244. package/src/codex/convergence.ts +580 -0
  245. package/src/codex/custom-model-catalog-migration.ts +176 -0
  246. package/src/codex/data/upstream-models.json +830 -0
  247. package/src/codex/desired-state.ts +230 -0
  248. package/src/codex/desktop-client-processes.ts +521 -0
  249. package/src/codex/exec-invocation.ts +22 -0
  250. package/src/codex/features.ts +1091 -0
  251. package/src/codex/generation.ts +202 -0
  252. package/src/codex/history-job.ts +347 -0
  253. package/src/codex/history-lock.ts +242 -0
  254. package/src/codex/history-migration-guardian.ts +115 -0
  255. package/src/codex/history-provider.ts +1075 -0
  256. package/src/codex/history-transition.ts +105 -0
  257. package/src/codex/history-worker.ts +204 -0
  258. package/src/codex/home.ts +206 -0
  259. package/src/codex/inject-coordination.ts +257 -0
  260. package/src/codex/inject.ts +1857 -0
  261. package/src/codex/injected-marker.ts +79 -0
  262. package/src/codex/integration-record.ts +266 -0
  263. package/src/codex/internal/catalog-writer.ts +203 -0
  264. package/src/codex/internal/history-writer.ts +105 -0
  265. package/src/codex/journal.ts +172 -0
  266. package/src/codex/main-account-cache.ts +56 -0
  267. package/src/codex/main-account.ts +40 -0
  268. package/src/codex/management-convergence.ts +114 -0
  269. package/src/codex/model-cache.ts +267 -0
  270. package/src/codex/native-main-admission.ts +47 -0
  271. package/src/codex/native-main-auth-temp.ts +187 -0
  272. package/src/codex/native-main-claim.ts +167 -0
  273. package/src/codex/native-main-lock-file.ts +162 -0
  274. package/src/codex/native-main-owner.ts +329 -0
  275. package/src/codex/native-profile-api.ts +247 -0
  276. package/src/codex/native-profile-manager.ts +1531 -0
  277. package/src/codex/native-profile-processes.ts +121 -0
  278. package/src/codex/native-profile-recovery.ts +99 -0
  279. package/src/codex/native-profile-stage-store.ts +387 -0
  280. package/src/codex/native-profile-startup.ts +348 -0
  281. package/src/codex/native-profile-store.ts +855 -0
  282. package/src/codex/native-profile-types.ts +120 -0
  283. package/src/codex/native-residue.ts +691 -0
  284. package/src/codex/paths.ts +78 -0
  285. package/src/codex/plugins-doctor.ts +242 -0
  286. package/src/codex/pool-rotation.ts +295 -0
  287. package/src/codex/project-config-warnings.ts +426 -0
  288. package/src/codex/prompt-journal.ts +311 -0
  289. package/src/codex/prompt-layers.ts +967 -0
  290. package/src/codex/prompt-lock.ts +143 -0
  291. package/src/codex/provider-adoption.ts +242 -0
  292. package/src/codex/quota-rejection.ts +224 -0
  293. package/src/codex/quota.ts +494 -0
  294. package/src/codex/refresh.ts +60 -0
  295. package/src/codex/routing.ts +1855 -0
  296. package/src/codex/runtime.ts +659 -0
  297. package/src/codex/shim.ts +1215 -0
  298. package/src/codex/subagent-defaults.ts +557 -0
  299. package/src/codex/subagent-model-fallback.ts +560 -0
  300. package/src/codex/sync.ts +238 -0
  301. package/src/codex/transition-state.ts +612 -0
  302. package/src/codex/upstream-host-health.ts +368 -0
  303. package/src/codex/user-identity.ts +374 -0
  304. package/src/codex/warmup.ts +192 -0
  305. package/src/codex/websocket-registry.ts +100 -0
  306. package/src/codex/write-coordination.ts +114 -0
  307. package/src/combos/failover.ts +140 -0
  308. package/src/combos/index.ts +44 -0
  309. package/src/combos/request.ts +64 -0
  310. package/src/combos/resolve.ts +232 -0
  311. package/src/combos/types.ts +392 -0
  312. package/src/config.ts +3270 -0
  313. package/src/generated/model-metadata.ts +144 -0
  314. package/src/github/star-state.ts +203 -0
  315. package/src/grok/inject.ts +540 -0
  316. package/src/grok/inspect.ts +45 -0
  317. package/src/grok/status.ts +127 -0
  318. package/src/grok/sync.ts +66 -0
  319. package/src/images/artifacts.ts +516 -0
  320. package/src/images/fulfill-video.ts +163 -0
  321. package/src/images/fulfill.ts +149 -0
  322. package/src/images/index.ts +4 -0
  323. package/src/images/loop.ts +922 -0
  324. package/src/images/plan.ts +133 -0
  325. package/src/images/synthetic-tool.ts +133 -0
  326. package/src/images/types.ts +41 -0
  327. package/src/images/xai-client.ts +141 -0
  328. package/src/images/xai-video-client.ts +163 -0
  329. package/src/index.ts +22 -0
  330. package/src/integrations/config-io.ts +151 -0
  331. package/src/integrations/journal.ts +315 -0
  332. package/src/integrations/merge.ts +135 -0
  333. package/src/integrations/native/ownership-preflight.ts +202 -0
  334. package/src/integrations/ownership.ts +111 -0
  335. package/src/integrations/registry.ts +108 -0
  336. package/src/integrations/serialize.ts +235 -0
  337. package/src/integrations/state.ts +290 -0
  338. package/src/integrations/store.ts +103 -0
  339. package/src/integrations/writer.ts +492 -0
  340. package/src/lib/abort.ts +146 -0
  341. package/src/lib/admin-secrets.ts +25 -0
  342. package/src/lib/admission.ts +83 -0
  343. package/src/lib/app-owned-memory-stores.ts +173 -0
  344. package/src/lib/app-owned-memory.ts +265 -0
  345. package/src/lib/bounded-body.ts +242 -0
  346. package/src/lib/bun-binary-validator.d.mts +3 -0
  347. package/src/lib/bun-binary-validator.mjs +18 -0
  348. package/src/lib/bun-runtime.ts +184 -0
  349. package/src/lib/bun-stream-caps.ts +127 -0
  350. package/src/lib/config-ownership.ts +438 -0
  351. package/src/lib/crash-guard.ts +344 -0
  352. package/src/lib/debug-log-buffer.ts +83 -0
  353. package/src/lib/debug-settings.ts +108 -0
  354. package/src/lib/debug.ts +31 -0
  355. package/src/lib/destination-policy.ts +316 -0
  356. package/src/lib/errors.ts +364 -0
  357. package/src/lib/eventstream-decoder.ts +253 -0
  358. package/src/lib/gcp-adc.ts +341 -0
  359. package/src/lib/injection-debug-log.ts +58 -0
  360. package/src/lib/local-management-attestation.ts +51 -0
  361. package/src/lib/open-url.ts +25 -0
  362. package/src/lib/pinned-http.ts +182 -0
  363. package/src/lib/privacy.ts +20 -0
  364. package/src/lib/process-control.ts +168 -0
  365. package/src/lib/provider-environment.ts +470 -0
  366. package/src/lib/provider-outbound.ts +203 -0
  367. package/src/lib/provider-url.ts +14 -0
  368. package/src/lib/proxy-env.ts +18 -0
  369. package/src/lib/redact.ts +510 -0
  370. package/src/lib/remodex-home.ts +616 -0
  371. package/src/lib/retry-after.ts +55 -0
  372. package/src/lib/service-secrets.ts +178 -0
  373. package/src/lib/shadow-call.ts +54 -0
  374. package/src/lib/sidecar-tracker.ts +52 -0
  375. package/src/lib/sse-decoder.ts +364 -0
  376. package/src/lib/state-store-registrations.ts +109 -0
  377. package/src/lib/state-store-sweeper.ts +184 -0
  378. package/src/lib/system-restart-contract.ts +73 -0
  379. package/src/lib/test-home-guard.ts +98 -0
  380. package/src/lib/token-estimate.ts +69 -0
  381. package/src/lib/translator-budget.ts +366 -0
  382. package/src/lib/upstream-reachability.ts +91 -0
  383. package/src/lib/upstream-retry.ts +508 -0
  384. package/src/lib/win-exec.ts +115 -0
  385. package/src/lib/win-paths.ts +68 -0
  386. package/src/lib/windows-elevation.ts +705 -0
  387. package/src/lib/windows-secret-acl.ts +817 -0
  388. package/src/lib/windows-user-principal.ts +283 -0
  389. package/src/lib/winsw.ts +402 -0
  390. package/src/model-sources.ts +73 -0
  391. package/src/oauth/anthropic-routing.ts +594 -0
  392. package/src/oauth/anthropic.ts +177 -0
  393. package/src/oauth/callback-server.ts +294 -0
  394. package/src/oauth/chatgpt.ts +150 -0
  395. package/src/oauth/command-code.ts +239 -0
  396. package/src/oauth/cursor.ts +231 -0
  397. package/src/oauth/github-copilot.ts +428 -0
  398. package/src/oauth/google-antigravity.ts +230 -0
  399. package/src/oauth/health.ts +443 -0
  400. package/src/oauth/index.ts +1280 -0
  401. package/src/oauth/key-providers.ts +128 -0
  402. package/src/oauth/kimi.ts +213 -0
  403. package/src/oauth/kiro-credentials.ts +726 -0
  404. package/src/oauth/kiro.ts +621 -0
  405. package/src/oauth/local-token-detect.ts +121 -0
  406. package/src/oauth/log.ts +48 -0
  407. package/src/oauth/login-cli.ts +163 -0
  408. package/src/oauth/pkce.ts +15 -0
  409. package/src/oauth/store.ts +655 -0
  410. package/src/oauth/token-guardian.ts +309 -0
  411. package/src/oauth/types.ts +62 -0
  412. package/src/oauth/xai.ts +241 -0
  413. package/src/providers/alibaba-region-backup.ts +75 -0
  414. package/src/providers/alibaba-region-migration.ts +156 -0
  415. package/src/providers/alibaba-region-startup.ts +36 -0
  416. package/src/providers/antigravity-models.ts +317 -0
  417. package/src/providers/api-keys.ts +140 -0
  418. package/src/providers/base-url-choices.ts +64 -0
  419. package/src/providers/codex-capacity.ts +288 -0
  420. package/src/providers/command-code-efforts.ts +85 -0
  421. package/src/providers/context-cap.ts +73 -0
  422. package/src/providers/derive.ts +451 -0
  423. package/src/providers/free-directory.ts +187 -0
  424. package/src/providers/github-copilot-transport.ts +56 -0
  425. package/src/providers/google-vertex-location.ts +14 -0
  426. package/src/providers/key-failover.ts +271 -0
  427. package/src/providers/kiro-models.ts +67 -0
  428. package/src/providers/label.ts +19 -0
  429. package/src/providers/model-discovery-limits.ts +16 -0
  430. package/src/providers/model-discovery.ts +361 -0
  431. package/src/providers/openai-sidecar.ts +235 -0
  432. package/src/providers/openai-tier-startup.ts +27 -0
  433. package/src/providers/openai-tiers.ts +301 -0
  434. package/src/providers/openai-virtual-models.ts +83 -0
  435. package/src/providers/openrouter-routing.ts +102 -0
  436. package/src/providers/provider-id-rewrite.ts +179 -0
  437. package/src/providers/quota.ts +1942 -0
  438. package/src/providers/reasoning-capabilities.ts +336 -0
  439. package/src/providers/registry.ts +2375 -0
  440. package/src/providers/slug-codec.ts +74 -0
  441. package/src/providers/xai-transport.ts +149 -0
  442. package/src/reasoning-effort.ts +243 -0
  443. package/src/responses/compaction.ts +124 -0
  444. package/src/responses/hosted-tool-policy.ts +9 -0
  445. package/src/responses/parser.ts +714 -0
  446. package/src/responses/reasoning-envelope.ts +60 -0
  447. package/src/responses/reasoning-replay-cache.ts +106 -0
  448. package/src/responses/schema.ts +159 -0
  449. package/src/responses/spill-store.ts +431 -0
  450. package/src/responses/state.ts +1039 -0
  451. package/src/responses/tool-groups.ts +19 -0
  452. package/src/router.ts +802 -0
  453. package/src/routing/analytics.ts +377 -0
  454. package/src/routing/capability.ts +205 -0
  455. package/src/routing/cost.ts +77 -0
  456. package/src/routing/evaluator.ts +444 -0
  457. package/src/routing/health.ts +401 -0
  458. package/src/routing/history/cursor.ts +43 -0
  459. package/src/routing/history/indexer.ts +605 -0
  460. package/src/routing/history/schema.ts +72 -0
  461. package/src/routing/profile-namespace.ts +15 -0
  462. package/src/routing/profile.ts +424 -0
  463. package/src/routing/quota.ts +145 -0
  464. package/src/routing/request-evidence.ts +45 -0
  465. package/src/routing/trace.ts +686 -0
  466. package/src/server/adapter-resolve.ts +83 -0
  467. package/src/server/auth-cors.ts +606 -0
  468. package/src/server/chat-completions.ts +379 -0
  469. package/src/server/claude-messages.ts +980 -0
  470. package/src/server/effort-policy.ts +251 -0
  471. package/src/server/github-copilot-responses-repair.ts +338 -0
  472. package/src/server/gui-static.ts +152 -0
  473. package/src/server/image-retry.ts +42 -0
  474. package/src/server/images.ts +485 -0
  475. package/src/server/index.ts +1633 -0
  476. package/src/server/lifecycle.ts +482 -0
  477. package/src/server/live.ts +609 -0
  478. package/src/server/management/agent-settings-routes.ts +1180 -0
  479. package/src/server/management/android-remote-routes.ts +390 -0
  480. package/src/server/management/api-access.ts +141 -0
  481. package/src/server/management/api-key-usage.ts +167 -0
  482. package/src/server/management/body.ts +35 -0
  483. package/src/server/management/combo-routes.ts +244 -0
  484. package/src/server/management/config-routes.ts +602 -0
  485. package/src/server/management/context.ts +88 -0
  486. package/src/server/management/integration-routes.ts +538 -0
  487. package/src/server/management/logs-usage-routes.ts +516 -0
  488. package/src/server/management/model-routes.ts +519 -0
  489. package/src/server/management/model-rows.ts +143 -0
  490. package/src/server/management/native-integration-routes.ts +781 -0
  491. package/src/server/management/oauth-account-routes.ts +573 -0
  492. package/src/server/management/provider-routes.ts +781 -0
  493. package/src/server/management/request-history-routes.ts +191 -0
  494. package/src/server/management/routing-analytics-routes.ts +74 -0
  495. package/src/server/management/routing-profile-routes.ts +384 -0
  496. package/src/server/management/shared.ts +277 -0
  497. package/src/server/management/sidebar-routes.ts +106 -0
  498. package/src/server/management/sync-response.ts +69 -0
  499. package/src/server/management/system-restart.ts +433 -0
  500. package/src/server/management/system-routes.ts +141 -0
  501. package/src/server/management/usage-summary-cache.ts +86 -0
  502. package/src/server/management-api.ts +269 -0
  503. package/src/server/management-auth.ts +353 -0
  504. package/src/server/memory-watchdog.ts +156 -0
  505. package/src/server/port-reclaim.ts +307 -0
  506. package/src/server/ports.ts +156 -0
  507. package/src/server/proxy-liveness.ts +326 -0
  508. package/src/server/proxy-stop.ts +92 -0
  509. package/src/server/readiness.ts +99 -0
  510. package/src/server/relay-eager.ts +353 -0
  511. package/src/server/relay.ts +1179 -0
  512. package/src/server/request-decompress.ts +132 -0
  513. package/src/server/request-log-conversation.ts +168 -0
  514. package/src/server/request-log.ts +1072 -0
  515. package/src/server/responses/collaboration.ts +409 -0
  516. package/src/server/responses/compact.ts +710 -0
  517. package/src/server/responses/core.ts +3561 -0
  518. package/src/server/responses/encrypted-payload.ts +308 -0
  519. package/src/server/responses/fetch-helpers.ts +171 -0
  520. package/src/server/responses/passthrough-error.ts +78 -0
  521. package/src/server/responses/policy-fallback.ts +152 -0
  522. package/src/server/responses/terminal-guard.ts +230 -0
  523. package/src/server/responses/upstream-error.ts +48 -0
  524. package/src/server/responses-image-gen-repair.ts +132 -0
  525. package/src/server/responses-item-id-repair.ts +272 -0
  526. package/src/server/responses-json-events.ts +52 -0
  527. package/src/server/responses-model-rewrite.ts +29 -0
  528. package/src/server/responses-snapshot-repair.ts +621 -0
  529. package/src/server/responses.ts +10 -0
  530. package/src/server/search.ts +181 -0
  531. package/src/server/sse-frame-buffer.ts +292 -0
  532. package/src/server/sse-payload-rewrite.ts +263 -0
  533. package/src/server/startup-action-control.ts +308 -0
  534. package/src/server/startup-health-cache.ts +119 -0
  535. package/src/server/system-env.ts +418 -0
  536. package/src/server/windows-tcp-drop.ts +184 -0
  537. package/src/server/windows-tray-control.ts +41 -0
  538. package/src/server/ws-bridge.ts +470 -0
  539. package/src/service-manager-probe.ts +824 -0
  540. package/src/service.ts +3011 -0
  541. package/src/stall-timeout.ts +20 -0
  542. package/src/storage/cleanup-job.ts +57 -0
  543. package/src/storage/cleanup.ts +3085 -0
  544. package/src/storage/policy-job.ts +457 -0
  545. package/src/storage/policy-scheduler.ts +40 -0
  546. package/src/storage/policy-worker.ts +59 -0
  547. package/src/storage/policy.ts +527 -0
  548. package/src/storage/restore-job.ts +299 -0
  549. package/src/storage/restore-worker.ts +58 -0
  550. package/src/storage/scanner.ts +238 -0
  551. package/src/storage/storage-mutation-coordinator.ts +139 -0
  552. package/src/storage/worker-lifecycle.ts +215 -0
  553. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  554. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  555. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  556. package/src/tray/assets/opencodex-tray.png +0 -0
  557. package/src/tray/windows-tray.ps1 +364 -0
  558. package/src/tray/windows.ts +738 -0
  559. package/src/types.ts +1531 -0
  560. package/src/update/badge.ts +72 -0
  561. package/src/update/desktop-release.ts +1620 -0
  562. package/src/update/index.ts +402 -0
  563. package/src/update/job.ts +1906 -0
  564. package/src/update/notify.ts +261 -0
  565. package/src/update/npm-cache-preflight.d.mts +47 -0
  566. package/src/update/npm-cache-preflight.mjs +201 -0
  567. package/src/update/npm-invocation.d.mts +23 -0
  568. package/src/update/npm-invocation.mjs +94 -0
  569. package/src/update/tray-update-plan.d.mts +18 -0
  570. package/src/update/tray-update-plan.mjs +38 -0
  571. package/src/usage/cost.ts +0 -0
  572. package/src/usage/debug.ts +97 -0
  573. package/src/usage/expected-prices.ts +283 -0
  574. package/src/usage/log.ts +695 -0
  575. package/src/usage/summary.ts +585 -0
  576. package/src/usage/totals.ts +14 -0
  577. package/src/vision/anthropic-describe.ts +185 -0
  578. package/src/vision/describe.ts +127 -0
  579. package/src/vision/index.ts +558 -0
  580. package/src/vision/reasoning.ts +55 -0
  581. package/src/web-search/anthropic-executor.ts +189 -0
  582. package/src/web-search/executor.ts +105 -0
  583. package/src/web-search/format-result.ts +89 -0
  584. package/src/web-search/index.ts +196 -0
  585. package/src/web-search/loop.ts +791 -0
  586. package/src/web-search/parse.ts +235 -0
  587. package/src/web-search/progress-stream.ts +342 -0
  588. package/src/web-search/synthetic-tool.ts +47 -0
@@ -0,0 +1,85 @@
1
+ import { parseUpstreamJsonPayload, safeUpstreamErrorString, sanitizeUpstreamErrorText } from "./upstream-http-error";
2
+
3
+ /** Pull the human detail out of the Google API error envelope `{error:{message,status,code}}`. */
4
+ function googleErrorDetail(payloadText: string): { message?: string; status?: string } {
5
+ const trimmed = payloadText.trim();
6
+ if (!trimmed || (!trimmed.startsWith("{") && !trimmed.startsWith("["))) {
7
+ return { message: trimmed || undefined };
8
+ }
9
+ const parsed = parseUpstreamJsonPayload(trimmed);
10
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
11
+ const err = (parsed as { error?: { message?: unknown; status?: unknown } }).error;
12
+ return {
13
+ message: safeUpstreamErrorString(err?.message),
14
+ status: safeUpstreamErrorString(err?.status),
15
+ };
16
+ }
17
+
18
+ function classifyGoogle(label: string, status: number | undefined, enumStatus: string | undefined, text: string): string {
19
+ const lower = `${enumStatus ?? ""} ${text}`.toLowerCase();
20
+ const quotaExhausted =
21
+ lower.includes("quotafailure") ||
22
+ lower.includes("quota exceeded") ||
23
+ lower.includes("exceeded your current quota") ||
24
+ lower.includes("billing");
25
+ if (enumStatus === "RESOURCE_EXHAUSTED" && quotaExhausted) return `${label} quota exhausted`;
26
+ if (status === 429 || enumStatus === "RESOURCE_EXHAUSTED" || lower.includes("rate limit")) {
27
+ return `${label} rate limit exceeded`;
28
+ }
29
+ if (status === 401 || enumStatus === "UNAUTHENTICATED" || lower.includes("unauthenticated") || lower.includes("invalid authentication") || lower.includes("expired")) {
30
+ return `${label} authentication failed`;
31
+ }
32
+ if (status === 403 || enumStatus === "PERMISSION_DENIED" || lower.includes("permission denied") || lower.includes("access denied")) {
33
+ return `${label} access denied`;
34
+ }
35
+ if (status === 503 || enumStatus === "UNAVAILABLE" || lower.includes("overloaded") || lower.includes("unavailable")) {
36
+ return `${label} server overloaded`;
37
+ }
38
+ if (status === 400 || status === 404 || enumStatus === "INVALID_ARGUMENT" || enumStatus === "NOT_FOUND" || lower.includes("invalid") || lower.includes("not found") || lower.includes("malformed")) {
39
+ return `${label} invalid request`;
40
+ }
41
+ return `${label} upstream error`;
42
+ }
43
+
44
+ /**
45
+ * Normalize a Google/Vertex/Antigravity HTTP error body into a short, classified, secret-redacted
46
+ * message. Mirrors `kiro-errors.ts`. `label` is the provider-facing prefix ("Vertex AI",
47
+ * "Antigravity").
48
+ */
49
+ export function safeGoogleHttpErrorMessage(label: string, status: number, payloadText: string): string {
50
+ const { message, status: enumStatus } = googleErrorDetail(payloadText);
51
+ const prefix = classifyGoogle(label, status, enumStatus, [message, enumStatus].filter(Boolean).join(" "));
52
+ const detail = message ? sanitizeUpstreamErrorText(message).slice(0, 500) : `HTTP ${status}`;
53
+ return `${prefix}: ${detail}`;
54
+ }
55
+
56
+ /** Vertex AI HTTP error message (label = "Vertex AI"). */
57
+ export function safeVertexHttpErrorMessage(status: number, payloadText: string): string {
58
+ return safeGoogleHttpErrorMessage("Vertex AI", status, payloadText);
59
+ }
60
+
61
+ /** Antigravity (Cloud Code Assist) HTTP error message (label = "Antigravity"). */
62
+ export function safeAntigravityHttpErrorMessage(status: number, payloadText: string): string {
63
+ return safeGoogleHttpErrorMessage("Antigravity", status, payloadText);
64
+ }
65
+
66
+ /** Google-family retryable HTTP set (mirrors Kiro). Quota-exhausted is classified above and not retried. */
67
+ export function retryableGoogleStatus(status: number): boolean {
68
+ return status === 429 || status === 500 || status === 502 || status === 503 || status === 504;
69
+ }
70
+
71
+ /**
72
+ * True when a 429 body indicates hard quota exhaustion (not a transient rate limit). Quota
73
+ * exhaustion is generally not expected to recover for hours (AIP-194), so it must NOT be retried —
74
+ * unlike a plain rate limit. The HTTP status alone can't distinguish the two, so the retry layer
75
+ * inspects the body with this.
76
+ */
77
+ export function isQuotaExhaustedBody(payloadText: string): boolean {
78
+ const { message, status } = googleErrorDetail(payloadText);
79
+ if (status !== "RESOURCE_EXHAUSTED") return false;
80
+ const lower = (message ?? "").toLowerCase();
81
+ return lower.includes("quotafailure")
82
+ || lower.includes("quota exceeded")
83
+ || lower.includes("exceeded your current quota")
84
+ || lower.includes("billing");
85
+ }
@@ -0,0 +1,100 @@
1
+ import type { AdapterFetchContext, AdapterRequest } from "./base";
2
+ import { isQuotaExhaustedBody, retryableGoogleStatus, safeGoogleHttpErrorMessage } from "./google-errors";
3
+ import { repairGoogleInvalidRequestBody } from "./google-wire-compiler";
4
+ import { normalizeUpstreamHttpErrorResponse, readDisplaySafeErrorPayloadText } from "./upstream-http-error";
5
+ import {
6
+ abortError,
7
+ cancelResponseBodyBestEffort,
8
+ fetchWithAttemptDeadline,
9
+ retryBackoffDelayMs,
10
+ sleepWithAbort,
11
+ } from "../lib/upstream-retry";
12
+
13
+ const GOOGLE_RETRY_ATTEMPTS = 3;
14
+ const GOOGLE_RETRY_BASE_MS = 250;
15
+ const GOOGLE_RETRY_MAX_MS = 2_000;
16
+
17
+ async function normalizeFinalGoogleError(label: string, res: Response, signal?: AbortSignal): Promise<Response> {
18
+ return normalizeUpstreamHttpErrorResponse(res, {
19
+ signal,
20
+ formatMessage: payloadText => safeGoogleHttpErrorMessage(label, res.status, payloadText),
21
+ });
22
+ }
23
+
24
+ /**
25
+ * Fetch a Google-family upstream (Vertex / Antigravity) with Kiro-style hardening: per-attempt
26
+ * timeout (`AbortSignal.any([parent, timeout])`), bounded retry on transient status / network
27
+ * errors, `Retry-After` honoring, jittered exponential backoff, and a classified + redacted final
28
+ * error body. `label` is the provider-facing prefix used in error messages.
29
+ */
30
+ export async function fetchGoogleWithRetry(label: string, request: AdapterRequest, ctx: AdapterFetchContext = {}): Promise<Response> {
31
+ const timeoutMs = ctx.timeoutMs ?? 200_000;
32
+ let lastError: unknown;
33
+ let activeRequest = request;
34
+ let compatibilityReplayUsed = false;
35
+ for (let attempt = 0; attempt < GOOGLE_RETRY_ATTEMPTS; attempt++) {
36
+ if (ctx.abortSignal?.aborted) throw abortError(ctx.abortSignal);
37
+ try {
38
+ const res = await fetchWithAttemptDeadline(activeRequest.url, {
39
+ method: activeRequest.method,
40
+ headers: activeRequest.headers,
41
+ body: activeRequest.body,
42
+ }, timeoutMs, ctx.abortSignal, ctx.stream);
43
+ if (res.status === 400 && !compatibilityReplayUsed) {
44
+ let payloadText = "";
45
+ try {
46
+ payloadText = await readDisplaySafeErrorPayloadText(res.clone(), ctx.abortSignal);
47
+ } catch (error) {
48
+ if (ctx.abortSignal?.aborted) throw error;
49
+ }
50
+ const repairedBody = repairGoogleInvalidRequestBody(activeRequest.body, payloadText);
51
+ if (repairedBody !== undefined) {
52
+ compatibilityReplayUsed = true;
53
+ activeRequest = { ...activeRequest, body: repairedBody };
54
+ cancelResponseBodyBestEffort(res);
55
+ attempt--; // The changed-request replay is separate from transient retry accounting.
56
+ continue;
57
+ }
58
+ }
59
+ if (!retryableGoogleStatus(res.status) || attempt === GOOGLE_RETRY_ATTEMPTS - 1) {
60
+ return ctx.returnRawErrors ? res : normalizeFinalGoogleError(label, res, ctx.abortSignal);
61
+ }
62
+ // A 429 may be a transient rate limit (retry) or hard quota exhaustion (do NOT retry —
63
+ // it won't recover for hours and burns retries). Peek the body to tell them apart.
64
+ if (res.status === 429 && !ctx.returnRawErrors) {
65
+ const peek = await readDisplaySafeErrorPayloadText(res, ctx.abortSignal);
66
+ if (isQuotaExhaustedBody(peek)) {
67
+ return normalizeUpstreamHttpErrorResponse(res, {
68
+ signal: ctx.abortSignal,
69
+ formatMessage: payloadText => safeGoogleHttpErrorMessage(label, res.status, payloadText || peek),
70
+ });
71
+ }
72
+ }
73
+ cancelResponseBodyBestEffort(res);
74
+ await sleepWithAbort(retryBackoffDelayMs(attempt, {
75
+ baseDelayMs: GOOGLE_RETRY_BASE_MS,
76
+ maxDelayMs: GOOGLE_RETRY_MAX_MS,
77
+ headers: res.headers,
78
+ }), ctx.abortSignal);
79
+ } catch (err) {
80
+ if (ctx.abortSignal?.aborted) throw err;
81
+ lastError = err;
82
+ if (attempt === GOOGLE_RETRY_ATTEMPTS - 1) throw err;
83
+ await sleepWithAbort(retryBackoffDelayMs(attempt, {
84
+ baseDelayMs: GOOGLE_RETRY_BASE_MS,
85
+ maxDelayMs: GOOGLE_RETRY_MAX_MS,
86
+ }), ctx.abortSignal);
87
+ }
88
+ }
89
+ throw lastError ?? new Error(`${label} fetch failed`);
90
+ }
91
+
92
+ /** Vertex AI retry wrapper. */
93
+ export function fetchVertexWithRetry(request: AdapterRequest, ctx: AdapterFetchContext = {}): Promise<Response> {
94
+ return fetchGoogleWithRetry("Vertex AI", request, ctx);
95
+ }
96
+
97
+ /** Antigravity (Cloud Code Assist) retry wrapper. */
98
+ export function fetchAntigravityWithRetry(request: AdapterRequest, ctx: AdapterFetchContext = {}): Promise<Response> {
99
+ return fetchGoogleWithRetry("Antigravity", request, ctx);
100
+ }
@@ -0,0 +1,173 @@
1
+ type Schema = Record<string, unknown>;
2
+
3
+ // Google documents this function-schema subset: type, nullable, required, format, description,
4
+ // properties, items, enum, anyOf, $ref, and $defs. We inline local refs and normalize anyOf, so
5
+ // only the eight scalar/container keywords below are ever emitted. Building from an allowlist
6
+ // prevents new MCP/JSON-Schema annotations from turning into provider-wide 400 responses.
7
+ const ALLOWED_TYPES = new Set(["string", "integer", "number", "boolean", "array", "object"]);
8
+ const MAX_SCHEMA_DEPTH = 24; // Google's documented nesting limit is 32; leave headroom for CCA.
9
+ const MAX_DEREF_DEPTH = 16;
10
+
11
+ function isRecord(value: unknown): value is Schema {
12
+ return !!value && typeof value === "object" && !Array.isArray(value);
13
+ }
14
+
15
+ function resolveRef(ref: string, defs: Map<string, unknown>): unknown {
16
+ // Only local pointers into the schema's own $defs/definitions are safe to inline.
17
+ const match = /^#\/(?:\$defs|definitions)\/(.+)$/.exec(ref);
18
+ if (!match) return undefined;
19
+ try {
20
+ return defs.get(decodeURIComponent(match[1].replace(/~1/g, "/").replace(/~0/g, "~")));
21
+ } catch {
22
+ return undefined;
23
+ }
24
+ }
25
+
26
+ function collectDefs(root: unknown, defs: Map<string, unknown>): void {
27
+ if (!isRecord(root)) return;
28
+ for (const bag of ["$defs", "definitions"] as const) {
29
+ const group = root[bag];
30
+ if (!isRecord(group)) continue;
31
+ for (const [name, value] of Object.entries(group)) {
32
+ if (!defs.has(name)) defs.set(name, value);
33
+ }
34
+ }
35
+ }
36
+
37
+ function normalizeType(value: unknown, out: Schema, preserveNullType: boolean): void {
38
+ const candidates = Array.isArray(value) ? value : [value];
39
+ let sawNull = false;
40
+
41
+ for (const candidate of candidates) {
42
+ if (typeof candidate !== "string") continue;
43
+ const type = candidate.toLowerCase();
44
+ if (type === "null") {
45
+ sawNull = true;
46
+ } else if (out.type === undefined && ALLOWED_TYPES.has(type)) {
47
+ out.type = type;
48
+ }
49
+ }
50
+
51
+ if (!sawNull) return;
52
+ if (out.type !== undefined) out.nullable = true;
53
+ else if (preserveNullType) out.type = "null";
54
+ else out.nullable = true;
55
+ }
56
+
57
+ function sanitizeEnum(value: unknown): string[] | undefined {
58
+ if (!Array.isArray(value)) return undefined;
59
+ const values = [...new Set(value.filter((item): item is string => typeof item === "string"))];
60
+ return values.length > 0 ? values : undefined;
61
+ }
62
+
63
+ function normalizeAnyOf(
64
+ value: unknown,
65
+ defs: Map<string, unknown>,
66
+ depth: number,
67
+ refDepth: number,
68
+ ): Schema {
69
+ if (!Array.isArray(value) || value.length === 0) return {};
70
+ const schemas = value.map(item => sanitizeSchema(item, defs, depth + 1, refDepth, true));
71
+
72
+ const nonNullSchemas = schemas.filter(schema => schema.type !== "null");
73
+ const nullSchemas = schemas.filter(schema => schema.type === "null");
74
+ if (
75
+ nonNullSchemas.length === 1
76
+ && nullSchemas.length > 0
77
+ && nullSchemas.every(schema => Object.keys(schema).every(key => key === "type"))
78
+ ) {
79
+ return { ...nonNullSchemas[0], nullable: true };
80
+ }
81
+
82
+ const type = schemas[0]?.type;
83
+ const sameType = schemas.length > 0 && schemas.every(schema => schema.type === type);
84
+ const enumOnly = schemas.every(schema => {
85
+ const allowedKeys = type === undefined ? new Set(["enum"]) : new Set(["type", "enum"]);
86
+ return Array.isArray(schema.enum) && Object.keys(schema).every(key => allowedKeys.has(key));
87
+ });
88
+ if (sameType && enumOnly && type !== "null") {
89
+ const values = sanitizeEnum(schemas.flatMap(schema => schema.enum as unknown[]));
90
+ if (values) return { ...(typeof type === "string" ? { type } : {}), enum: values };
91
+ }
92
+
93
+ // CCA's Claude bridge turns typed anyOf branches into an invalid input_schema. Widen only this
94
+ // node when a union cannot be collapsed losslessly; parent annotations and structure survive.
95
+ return {};
96
+ }
97
+
98
+ function sanitizeProperties(
99
+ value: unknown,
100
+ defs: Map<string, unknown>,
101
+ depth: number,
102
+ refDepth: number,
103
+ ): Record<string, Schema> | undefined {
104
+ if (!isRecord(value)) return undefined;
105
+ const properties: Record<string, Schema> = Object.create(null) as Record<string, Schema>;
106
+ for (const [name, schema] of Object.entries(value)) {
107
+ // Property names form a name bag and must never be interpreted as schema keywords.
108
+ properties[name] = sanitizeSchema(schema, defs, depth + 1, refDepth, false);
109
+ }
110
+ return properties;
111
+ }
112
+
113
+ function sanitizeSchema(
114
+ node: unknown,
115
+ defs: Map<string, unknown>,
116
+ depth: number,
117
+ refDepth: number,
118
+ preserveNullType: boolean,
119
+ ): Schema {
120
+ if (depth >= MAX_SCHEMA_DEPTH || !isRecord(node)) return {};
121
+
122
+ if (typeof node.$ref === "string" && refDepth < MAX_DEREF_DEPTH) {
123
+ const target = resolveRef(node.$ref, defs);
124
+ if (isRecord(target)) {
125
+ const merged: Schema = { ...target };
126
+ for (const [key, value] of Object.entries(node)) {
127
+ if (key !== "$ref") merged[key] = value;
128
+ }
129
+ return sanitizeSchema(merged, defs, depth, refDepth + 1, preserveNullType);
130
+ }
131
+ }
132
+
133
+ const out: Schema = {};
134
+ normalizeType(node.type, out, preserveNullType);
135
+
136
+ if (typeof node.nullable === "boolean") out.nullable = node.nullable;
137
+ if (typeof node.description === "string") out.description = node.description;
138
+ if (typeof node.format === "string") out.format = node.format;
139
+
140
+ const enumValues = sanitizeEnum(node.enum ?? (typeof node.const === "string" ? [node.const] : undefined));
141
+ if (enumValues) out.enum = enumValues;
142
+
143
+ const properties = sanitizeProperties(node.properties, defs, depth, refDepth);
144
+ if (properties) out.properties = properties;
145
+
146
+ if (isRecord(node.items)) {
147
+ out.items = sanitizeSchema(node.items, defs, depth + 1, refDepth, false);
148
+ }
149
+
150
+ if (Array.isArray(node.required)) {
151
+ out.required = [...new Set(node.required.filter((item): item is string => typeof item === "string"))];
152
+ }
153
+
154
+ if (node.anyOf !== undefined) Object.assign(out, normalizeAnyOf(node.anyOf, defs, depth, refDepth));
155
+ return out;
156
+ }
157
+
158
+ export function sanitizeGeminiToolParameters(parameters: unknown): Record<string, unknown> {
159
+ try {
160
+ const defs = new Map<string, unknown>();
161
+ collectDefs(parameters, defs);
162
+ const root = sanitizeSchema(parameters, defs, 0, 0, false);
163
+
164
+ // Function arguments are always an object. Claude additionally rejects root composition and a
165
+ // missing root type even when those forms are valid general-purpose JSON Schema.
166
+ root.type = "object";
167
+ if (!isRecord(root.properties)) root.properties = {};
168
+ return root;
169
+ } catch {
170
+ // Last-resort containment: no third-party schema may break every tool in the request.
171
+ return { type: "object", properties: {} };
172
+ }
173
+ }
@@ -0,0 +1,24 @@
1
+ import { redactSecretString } from "../lib/redact";
2
+
3
+ /** Gemini/Vertex finishReason values that mean the turn was cut off, not cleanly stopped. */
4
+ const TRUNCATION_REASONS = new Set(["MAX_TOKENS", "MALFORMED_FUNCTION_CALL"]);
5
+
6
+ export function isVertexTruncationReason(finishReason: string | undefined): boolean {
7
+ return finishReason !== undefined && TRUNCATION_REASONS.has(finishReason);
8
+ }
9
+
10
+ export function vertexTruncationErrorMessage(reason?: string): string {
11
+ const suffix = reason ? ` (${redactSecretString(reason).slice(0, 160)})` : "";
12
+ return `Vertex AI response truncated upstream before the turn completed${suffix}`;
13
+ }
14
+
15
+ /**
16
+ * Whether a finished turn must fail closed. A truncation reason arriving mid tool call always
17
+ * does. MALFORMED_FUNCTION_CALL fails closed even with zero started calls: the malformed call
18
+ * is dropped upstream and usually never materializes as a part, so the turn is incomplete
19
+ * despite looking empty. MAX_TOKENS with no started call stays a plain token-limit stop.
20
+ */
21
+ export function isVertexTruncatedTurn(finishReason: string | undefined, toolCallsStarted: number): boolean {
22
+ if (!isVertexTruncationReason(finishReason)) return false;
23
+ return toolCallsStarted > 0 || finishReason === "MALFORMED_FUNCTION_CALL";
24
+ }
@@ -0,0 +1,232 @@
1
+ import { createHash } from "node:crypto";
2
+ import { sanitizeGeminiToolParameters } from "./google-tool-schema";
3
+
4
+ type JsonObject = Record<string, unknown>;
5
+
6
+ const GOOGLE_TOOL_NAME = /^[A-Za-z_][A-Za-z0-9_-]{0,63}$/;
7
+ const GOOGLE_THINKING_LEVELS = new Set(["minimal", "low", "medium", "high"]);
8
+
9
+ function isObject(value: unknown): value is JsonObject {
10
+ return !!value && typeof value === "object" && !Array.isArray(value);
11
+ }
12
+
13
+ function toolNameCodec(names: readonly string[]): {
14
+ toWire: (name: string) => string;
15
+ fromWire: (name: string) => string;
16
+ } {
17
+ const toWire = new Map<string, string>();
18
+ const fromWire = new Map<string, string>();
19
+ const used = new Set<string>();
20
+
21
+ for (const name of names) {
22
+ if (toWire.has(name)) continue;
23
+ if (GOOGLE_TOOL_NAME.test(name) && !used.has(name)) {
24
+ toWire.set(name, name);
25
+ fromWire.set(name, name);
26
+ used.add(name);
27
+ continue;
28
+ }
29
+
30
+ let cleaned = name.replace(/[^A-Za-z0-9_-]/g, "_");
31
+ if (!/^[A-Za-z_]/.test(cleaned)) cleaned = `_${cleaned}`;
32
+ const prefix = (cleaned || "tool").slice(0, 55);
33
+ for (let salt = 0; ; salt++) {
34
+ const hashInput = salt === 0 ? name : `${name}#${salt}`;
35
+ const suffix = createHash("sha256").update(hashInput).digest("hex").slice(0, 8);
36
+ const candidate = `${prefix}_${suffix}`;
37
+ if (used.has(candidate)) continue;
38
+ toWire.set(name, candidate);
39
+ fromWire.set(candidate, name);
40
+ used.add(candidate);
41
+ break;
42
+ }
43
+ }
44
+
45
+ return {
46
+ toWire: name => toWire.get(name) ?? name,
47
+ fromWire: name => fromWire.get(name) ?? name,
48
+ };
49
+ }
50
+
51
+ function collectToolNames(body: JsonObject): string[] {
52
+ const names: string[] = [];
53
+ if (Array.isArray(body.tools)) {
54
+ for (const rawTool of body.tools) {
55
+ if (!isObject(rawTool) || !Array.isArray(rawTool.functionDeclarations)) continue;
56
+ for (const rawDeclaration of rawTool.functionDeclarations) {
57
+ if (isObject(rawDeclaration) && typeof rawDeclaration.name === "string") names.push(rawDeclaration.name);
58
+ }
59
+ }
60
+ }
61
+ if (Array.isArray(body.contents)) {
62
+ for (const rawContent of body.contents) {
63
+ if (!isObject(rawContent) || !Array.isArray(rawContent.parts)) continue;
64
+ for (const rawPart of rawContent.parts) {
65
+ if (!isObject(rawPart)) continue;
66
+ for (const key of ["functionCall", "functionResponse"]) {
67
+ const call = rawPart[key];
68
+ if (isObject(call) && typeof call.name === "string") names.push(call.name);
69
+ }
70
+ }
71
+ }
72
+ }
73
+ return names;
74
+ }
75
+
76
+ function compileContents(value: unknown, toWireName: (name: string) => string): unknown[] | undefined {
77
+ if (!Array.isArray(value)) return undefined;
78
+ return value.map(rawContent => {
79
+ if (!isObject(rawContent)) return {};
80
+ const content = { ...rawContent };
81
+ if (!Array.isArray(rawContent.parts)) return content;
82
+ content.parts = rawContent.parts.map(rawPart => {
83
+ if (!isObject(rawPart)) return {};
84
+ const part = { ...rawPart };
85
+ for (const key of ["functionCall", "functionResponse"]) {
86
+ const call = rawPart[key];
87
+ if (isObject(call) && typeof call.name === "string") {
88
+ part[key] = { ...call, name: toWireName(call.name) };
89
+ }
90
+ }
91
+ return part;
92
+ });
93
+ return content;
94
+ });
95
+ }
96
+
97
+ function compileTools(value: unknown, toWireName: (name: string) => string): unknown[] | undefined {
98
+ if (!Array.isArray(value)) return undefined;
99
+ const tools = value.flatMap(rawTool => {
100
+ if (!isObject(rawTool) || !Array.isArray(rawTool.functionDeclarations)) return [];
101
+ const functionDeclarations = rawTool.functionDeclarations.flatMap(rawDeclaration => {
102
+ if (!isObject(rawDeclaration) || typeof rawDeclaration.name !== "string") return [];
103
+ return [{
104
+ name: toWireName(rawDeclaration.name),
105
+ ...(typeof rawDeclaration.description === "string" ? { description: rawDeclaration.description } : {}),
106
+ parameters: sanitizeGeminiToolParameters(rawDeclaration.parameters),
107
+ }];
108
+ });
109
+ return functionDeclarations.length > 0 ? [{ functionDeclarations }] : [];
110
+ });
111
+ return tools.length > 0 ? tools : undefined;
112
+ }
113
+
114
+ function finiteNumber(value: unknown): number | undefined {
115
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
116
+ }
117
+
118
+ function compileGenerationConfig(value: unknown): JsonObject | undefined {
119
+ if (!isObject(value)) return undefined;
120
+ const out: JsonObject = {};
121
+ const maxOutputTokens = finiteNumber(value.maxOutputTokens);
122
+ if (maxOutputTokens !== undefined && maxOutputTokens > 0) out.maxOutputTokens = Math.floor(maxOutputTokens);
123
+ const temperature = finiteNumber(value.temperature);
124
+ if (temperature !== undefined && temperature >= 0) out.temperature = Math.min(2, temperature);
125
+ const topP = finiteNumber(value.topP);
126
+ if (topP !== undefined && topP >= 0) out.topP = Math.min(1, topP);
127
+ if (Array.isArray(value.stopSequences)) {
128
+ const stopSequences = [...new Set(value.stopSequences.filter(
129
+ (item): item is string => typeof item === "string" && item.length > 0,
130
+ ))].slice(0, 5);
131
+ if (stopSequences.length > 0) out.stopSequences = stopSequences;
132
+ }
133
+ if (isObject(value.thinkingConfig) && typeof value.thinkingConfig.thinkingLevel === "string") {
134
+ const raw = value.thinkingConfig.thinkingLevel.toLowerCase();
135
+ const thinkingLevel = GOOGLE_THINKING_LEVELS.has(raw)
136
+ ? raw
137
+ : (["xhigh", "max", "ultra"].includes(raw) ? "high" : undefined);
138
+ if (thinkingLevel) out.thinkingConfig = { thinkingLevel };
139
+ }
140
+ if (Array.isArray(value.responseModalities)) {
141
+ const valid = value.responseModalities.filter((m): m is string => typeof m === "string" && ["TEXT", "IMAGE", "AUDIO"].includes(m));
142
+ if (valid.length > 0) out.responseModalities = valid;
143
+ }
144
+ return Object.keys(out).length > 0 ? out : undefined;
145
+ }
146
+
147
+ function compileToolConfig(value: unknown, toWireName: (name: string) => string): JsonObject | undefined {
148
+ if (!isObject(value) || !isObject(value.functionCallingConfig)) return undefined;
149
+ const raw = value.functionCallingConfig;
150
+ const out: JsonObject = {};
151
+ if (typeof raw.mode === "string" && ["AUTO", "ANY", "NONE", "VALIDATED"].includes(raw.mode.toUpperCase())) {
152
+ out.mode = raw.mode.toUpperCase();
153
+ }
154
+ if (Array.isArray(raw.allowedFunctionNames)) {
155
+ const names = raw.allowedFunctionNames
156
+ .filter((name): name is string => typeof name === "string")
157
+ .map(toWireName);
158
+ if (names.length > 0) out.allowedFunctionNames = names;
159
+ }
160
+ return Object.keys(out).length > 0 ? { functionCallingConfig: out } : undefined;
161
+ }
162
+
163
+ /**
164
+ * Final trust boundary for every Google-family request. The adapter may build a convenient
165
+ * Gemini-shaped object; only this compiler is allowed to decide what reaches the wire.
166
+ */
167
+ export function compileGoogleWireBody(input: unknown): {
168
+ body: JsonObject;
169
+ restoreToolName: (name: string) => string;
170
+ } {
171
+ const source = isObject(input) ? input : {};
172
+ const names = toolNameCodec(collectToolNames(source));
173
+ const body: JsonObject = {};
174
+ const contents = compileContents(source.contents, names.toWire);
175
+ if (contents) body.contents = contents;
176
+ if (isObject(source.systemInstruction)) body.systemInstruction = source.systemInstruction;
177
+ const tools = compileTools(source.tools, names.toWire);
178
+ if (tools) body.tools = tools;
179
+ const generationConfig = compileGenerationConfig(source.generationConfig);
180
+ if (generationConfig) body.generationConfig = generationConfig;
181
+ const toolConfig = compileToolConfig(source.toolConfig, names.toWire);
182
+ if (toolConfig) body.toolConfig = toolConfig;
183
+ if (typeof source.sessionId === "string" && source.sessionId.length > 0) body.sessionId = source.sessionId;
184
+ return { body, restoreToolName: names.fromWire };
185
+ }
186
+
187
+ function functionDeclarations(root: JsonObject): JsonObject[] {
188
+ if (!Array.isArray(root.tools)) return [];
189
+ return root.tools.flatMap(rawTool => {
190
+ if (!isObject(rawTool) || !Array.isArray(rawTool.functionDeclarations)) return [];
191
+ return rawTool.functionDeclarations.filter(isObject);
192
+ });
193
+ }
194
+
195
+ /** Build a changed request for one known-safe replay of an INVALID_ARGUMENT response. */
196
+ export function repairGoogleInvalidRequestBody(body: string, errorPayload: string): string | undefined {
197
+ const schemaError = /(?:input[_ ]schema|json schema|function[_ ]declarations?|x-mcp-header)/i.test(errorPayload);
198
+ const thinkingError = /thinking[_ ]?(?:config|level)/i.test(errorPayload);
199
+ if (!schemaError && !thinkingError) return undefined;
200
+ let parsed: unknown;
201
+ try {
202
+ parsed = JSON.parse(body) as unknown;
203
+ } catch {
204
+ return undefined;
205
+ }
206
+ if (!isObject(parsed)) return undefined;
207
+ const root = isObject(parsed.request) ? parsed.request : parsed;
208
+ let changed = false;
209
+
210
+ if (thinkingError && isObject(root.generationConfig) && "thinkingConfig" in root.generationConfig) {
211
+ delete root.generationConfig.thinkingConfig;
212
+ if (Object.keys(root.generationConfig).length === 0) delete root.generationConfig;
213
+ changed = true;
214
+ }
215
+
216
+ if (schemaError) {
217
+ const declarations = functionDeclarations(root);
218
+ if (declarations.length > 0) {
219
+ const indexed = /tools(?:\.|\[)(\d+)(?:\])?\.custom\.input_schema/i.exec(errorPayload)?.[1]
220
+ ?? /function[_]?declarations(?:\.|\[)(\d+)/i.exec(errorPayload)?.[1];
221
+ const index = indexed === undefined ? -1 : Number.parseInt(indexed, 10);
222
+ const rejected = declarations[index];
223
+ const targets = rejected ? [rejected] : declarations;
224
+ for (const declaration of targets) {
225
+ declaration.parameters = { type: "object", properties: {} };
226
+ delete declaration.parametersJsonSchema;
227
+ }
228
+ changed = true;
229
+ }
230
+ }
231
+ return changed ? JSON.stringify(parsed) : undefined;
232
+ }