@bitkyc08/opencodex 2.84.0 → 2.87.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 (518) hide show
  1. package/README.md +0 -4
  2. package/bin/ocx.mjs +61 -3
  3. package/gui/dist/assets/App-ZfYbLHkB.js +58 -0
  4. package/gui/dist/assets/App-wT3mXqFz.css +1 -0
  5. package/gui/dist/assets/{Tray-C9TGtwad.js → Tray-DCd-A1az.js} +1 -1
  6. package/gui/dist/assets/index-CfYDMj34.js +94 -0
  7. package/gui/dist/assets/index-DPeB9HpV.css +1 -0
  8. package/gui/dist/assets/quota-summary-ChvmKGOk.js +1 -0
  9. package/gui/dist/index.html +2 -2
  10. package/package.json +1 -2
  11. package/src/adapters/anthropic/beta-allowlist.ts +91 -11
  12. package/src/adapters/anthropic/beta-body-pairs.ts +93 -0
  13. package/src/adapters/anthropic/client-identity.ts +1 -1
  14. package/src/adapters/anthropic/passthrough.ts +16 -3
  15. package/src/adapters/anthropic-progress.ts +84 -0
  16. package/src/adapters/anthropic.ts +108 -21
  17. package/src/adapters/azure.ts +19 -1
  18. package/src/adapters/base.ts +2 -0
  19. package/src/adapters/claude-cli/adapter.ts +111 -23
  20. package/src/adapters/claude-cli/profiles.ts +2 -1
  21. package/src/adapters/claude-cli/stable-replay.ts +108 -0
  22. package/src/adapters/claude-cli/usage-admission.ts +230 -0
  23. package/src/adapters/client-fingerprint.ts +24 -0
  24. package/src/adapters/coding-agent/protocol.ts +1 -1
  25. package/src/adapters/coding-agent/turn.ts +40 -11
  26. package/src/adapters/cursor/arg-codec.ts +17 -5
  27. package/src/adapters/cursor/catalog.ts +8 -0
  28. package/src/adapters/cursor/effort-map.ts +3 -0
  29. package/src/adapters/cursor/freeform-args.ts +75 -0
  30. package/src/adapters/cursor/protobuf-events.ts +36 -23
  31. package/src/adapters/dsh-account.ts +97 -0
  32. package/src/adapters/google-antigravity-wire.ts +22 -1
  33. package/src/adapters/google.ts +37 -10
  34. package/src/adapters/openai-chat/messages.ts +4 -3
  35. package/src/adapters/openai-chat/passthrough.ts +8 -2
  36. package/src/adapters/openai-chat/reasoning-replay.ts +52 -0
  37. package/src/adapters/openai-chat/response-events.ts +59 -1
  38. package/src/adapters/openai-chat.ts +8 -5
  39. package/src/adapters/openai-responses/compaction-search-history.ts +14 -7
  40. package/src/adapters/openai-responses/passthrough.ts +57 -125
  41. package/src/adapters/openai-responses/request-strips.ts +25 -3
  42. package/src/adapters/openai-responses/transport.ts +81 -0
  43. package/src/adapters/qoder/adapter.ts +44 -3
  44. package/src/adapters/registry.ts +5 -0
  45. package/src/adapters/zed.ts +26 -1
  46. package/src/advisor/activity.ts +55 -0
  47. package/src/advisor/budget.ts +62 -0
  48. package/src/advisor/consult.ts +223 -0
  49. package/src/advisor/context.ts +238 -0
  50. package/src/advisor/disclosure.ts +20 -0
  51. package/src/advisor/evidence-tool.ts +21 -0
  52. package/src/advisor/evidence.ts +117 -0
  53. package/src/advisor/runtime.ts +353 -0
  54. package/src/advisor/settings.ts +144 -0
  55. package/src/advisor/state.ts +369 -0
  56. package/src/advisor/synthetic-tool.ts +33 -0
  57. package/src/bridge/errors.ts +24 -1
  58. package/src/bridge/internal.ts +3 -1
  59. package/src/bridge/response-json.ts +18 -3
  60. package/src/bridge/sse.ts +58 -8
  61. package/src/bridge/terminal-refusal.ts +59 -0
  62. package/src/chat/inbound.ts +30 -6
  63. package/src/chat/outbound.ts +5 -0
  64. package/src/claude/desktop-3p-library.ts +72 -7
  65. package/src/claude/desktop-3p.ts +75 -19
  66. package/src/claude/desktop-first-party.ts +1 -1
  67. package/src/claude/desktop-picker-platform.ts +4 -0
  68. package/src/claude/desktop-picker-profile.ts +11 -4
  69. package/src/claude/desktop-picker.ts +15 -8
  70. package/src/claude/desktop-profile.ts +10 -1
  71. package/src/claude/desktop-remote-store-io.ts +5 -3
  72. package/src/claude/desktop-system-proxy.ts +50 -4
  73. package/src/claude/inbound-content-options.ts +11 -0
  74. package/src/claude/inbound.ts +154 -50
  75. package/src/claude/intercept/local-ca.ts +8 -1
  76. package/src/claude/intercept/picker-ca-startup.ts +2 -1
  77. package/src/claude/intercept/picker-runtime.ts +6 -5
  78. package/src/claude/intercept/picker-trust-windows.ts +338 -0
  79. package/src/claude/intercept/picker-trust.ts +19 -0
  80. package/src/claude/intercept/port-policy.ts +30 -0
  81. package/src/claude/intercept/runtime.ts +97 -94
  82. package/src/claude/model-default-settings.ts +154 -0
  83. package/src/claude/model-info.ts +7 -7
  84. package/src/claude/outbound.ts +51 -19
  85. package/src/cli/account-api.ts +1 -0
  86. package/src/cli/account-policy-dto.ts +6 -0
  87. package/src/cli/account-policy.ts +34 -5
  88. package/src/cli/account-preservation.ts +44 -0
  89. package/src/cli/account.ts +8 -2
  90. package/src/cli/advisor.ts +165 -0
  91. package/src/cli/auxiliary-listener-preflight.ts +37 -0
  92. package/src/cli/capabilities-accounts.ts +20 -1
  93. package/src/cli/capabilities-agents-routing.ts +23 -2
  94. package/src/cli/capabilities-base.ts +39 -11
  95. package/src/cli/capabilities-observe-system.ts +63 -3
  96. package/src/cli/capabilities-provider-models.ts +11 -0
  97. package/src/cli/chatgpt-command.ts +35 -14
  98. package/src/cli/claude.ts +46 -6
  99. package/src/cli/codex-cli-update.ts +151 -41
  100. package/src/cli/codex-provider.ts +44 -0
  101. package/src/cli/combo-input.ts +10 -1
  102. package/src/cli/combo-result.ts +1 -1
  103. package/src/cli/combo.ts +2 -1
  104. package/src/cli/cross-home-owner.ts +17 -14
  105. package/src/cli/dispatch.ts +30 -5
  106. package/src/cli/doctor.ts +15 -1
  107. package/src/cli/ensure-desktop-cold-start.ts +382 -0
  108. package/src/cli/export-command.ts +1 -1
  109. package/src/cli/help.ts +4 -2
  110. package/src/cli/index.ts +14 -5
  111. package/src/cli/integration-plan-dto.ts +3 -0
  112. package/src/cli/log-history.ts +172 -0
  113. package/src/cli/models-runtime-subcommands.ts +1 -0
  114. package/src/cli/models-runtime.ts +72 -8
  115. package/src/cli/observe-stream.ts +2 -0
  116. package/src/cli/observe.ts +16 -4
  117. package/src/cli/provider.ts +27 -5
  118. package/src/cli/registry.ts +41 -9
  119. package/src/cli/restart-scope.ts +3 -1
  120. package/src/cli/runtime-api.ts +5 -3
  121. package/src/cli/system-command.ts +40 -8
  122. package/src/cli/uninstall-client-state.ts +32 -0
  123. package/src/cli/usage-compare.ts +309 -0
  124. package/src/cli/usage-model-search.ts +4 -4
  125. package/src/cli/usage-report.ts +2 -2
  126. package/src/cli/v2.ts +1 -1
  127. package/src/client/machine-listener.ts +1 -3
  128. package/src/client/runtime.ts +1 -0
  129. package/src/clients/client-path.ts +51 -0
  130. package/src/clients/config-export/contracts.ts +3 -1
  131. package/src/clients/config-export/model-metadata.ts +3 -2
  132. package/src/clients/config-export/qoder.ts +93 -0
  133. package/src/clients/config-export.ts +35 -48
  134. package/src/clients/gentle-shell-path.ts +87 -0
  135. package/src/codex/account-auto-switch.ts +2 -0
  136. package/src/codex/account-identity.ts +29 -0
  137. package/src/codex/account-label.ts +1 -1
  138. package/src/codex/account-lifecycle.ts +21 -5
  139. package/src/codex/account-preservation.ts +28 -0
  140. package/src/codex/account-use-remaining.ts +23 -0
  141. package/src/codex/app-server-processes.ts +97 -7
  142. package/src/codex/app-server-restart-service.ts +55 -4
  143. package/src/codex/auth-api/account-list.ts +4 -0
  144. package/src/codex/auth-api/account-pause-group.ts +6 -50
  145. package/src/codex/auth-api/account-preservation.ts +57 -0
  146. package/src/codex/auth-api/pool-mode-gate.ts +5 -2
  147. package/src/codex/auth-api/routes.ts +8 -0
  148. package/src/codex/auth-api/use-remaining-route.ts +36 -0
  149. package/src/codex/auth-api.ts +0 -1
  150. package/src/codex/auth-context.ts +81 -7
  151. package/src/codex/autostart-health.ts +4 -0
  152. package/src/codex/catalog/auto-review.ts +20 -3
  153. package/src/codex/catalog/build-entries.ts +19 -2
  154. package/src/codex/catalog/combo-member.ts +14 -5
  155. package/src/codex/catalog/configured-tiers.ts +50 -0
  156. package/src/codex/catalog/effort.ts +4 -1
  157. package/src/codex/catalog/gather-capture.ts +2 -0
  158. package/src/codex/catalog/metadata.ts +11 -9
  159. package/src/codex/catalog/model-hints.ts +42 -19
  160. package/src/codex/catalog/model-visibility.ts +3 -1
  161. package/src/codex/catalog/native-ultrafast.ts +106 -0
  162. package/src/codex/catalog/parsing.ts +35 -86
  163. package/src/codex/catalog/provider-models.ts +40 -34
  164. package/src/codex/catalog/retained-sync.ts +2 -0
  165. package/src/codex/catalog/routed-gather.ts +33 -16
  166. package/src/codex/catalog/vendor-context.ts +82 -0
  167. package/src/codex/cli-install-provenance.ts +105 -17
  168. package/src/codex/cli-update-plan.ts +545 -0
  169. package/src/codex/config-write-lock.ts +63 -4
  170. package/src/codex/convergence.ts +2 -0
  171. package/src/codex/desktop-app/picker-freshness.ts +96 -0
  172. package/src/codex/desktop-app/types.ts +2 -0
  173. package/src/codex/desktop-app/windows.ts +29 -16
  174. package/src/codex/desktop-app-restart.ts +25 -2
  175. package/src/codex/desktop-compatibility/certificate-service.ts +99 -0
  176. package/src/codex/desktop-compatibility/certificate-store.ts +193 -0
  177. package/src/codex/desktop-compatibility/connection-store.ts +87 -0
  178. package/src/codex/desktop-compatibility/installed-build.ts +73 -0
  179. package/src/codex/desktop-compatibility/json-body.ts +29 -0
  180. package/src/codex/desktop-compatibility/native-identity.ts +62 -0
  181. package/src/codex/desktop-compatibility/relay-listener.ts +93 -0
  182. package/src/codex/desktop-compatibility/routing-binding.ts +10 -0
  183. package/src/codex/desktop-compatibility/routing-preflight.ts +69 -0
  184. package/src/codex/desktop-compatibility/runtime-ownership.ts +28 -0
  185. package/src/codex/desktop-compatibility/runtime.ts +182 -0
  186. package/src/codex/desktop-compatibility/service.ts +30 -0
  187. package/src/codex/desktop-compatibility/startup-settings.ts +50 -0
  188. package/src/codex/desktop-compatibility/usage-activation.ts +86 -0
  189. package/src/codex/desktop-compatibility/usage-controlled-fetch.ts +59 -0
  190. package/src/codex/desktop-compatibility/usage-controller.ts +107 -0
  191. package/src/codex/desktop-compatibility/usage-policy.ts +59 -0
  192. package/src/codex/desktop-compatibility/usage-refresh.ts +33 -0
  193. package/src/codex/desktop-compatibility/usage-sse-controller.ts +86 -0
  194. package/src/codex/desktop-compatibility/windows-activation-source.ts +44 -0
  195. package/src/codex/desktop-compatibility/windows-certificate-trust.ts +81 -0
  196. package/src/codex/desktop-compatibility/windows-key-protection.ts +165 -0
  197. package/src/codex/desktop-compatibility/windows-package-command.ts +86 -0
  198. package/src/codex/desktop-compatibility/windows-package-launch.ts +28 -0
  199. package/src/codex/features.ts +85 -45
  200. package/src/codex/history-provider.ts +1 -1
  201. package/src/codex/inject/config-write-section.ts +4 -1
  202. package/src/codex/inject/history-failure.ts +27 -0
  203. package/src/codex/inject/remove.ts +18 -6
  204. package/src/codex/inject/restore.ts +24 -2
  205. package/src/codex/inject/routing-classify.ts +4 -3
  206. package/src/codex/inject.ts +18 -27
  207. package/src/codex/journal.ts +16 -1
  208. package/src/codex/main-account-hard-lock.ts +30 -1
  209. package/src/codex/main-account.ts +99 -15
  210. package/src/codex/native-main-refresh-mode.ts +217 -0
  211. package/src/codex/native-profile-startup.ts +1 -1
  212. package/src/codex/ocx-compaction-history.ts +12 -10
  213. package/src/codex/paths.ts +86 -1
  214. package/src/codex/provider-routing.ts +174 -0
  215. package/src/codex/refresh.ts +2 -2
  216. package/src/codex/routing/health-store.ts +2 -2
  217. package/src/codex/routing/pool-recovery.ts +79 -0
  218. package/src/codex/routing/selection.ts +4 -3
  219. package/src/codex/routing/thread-affinity.ts +1 -1
  220. package/src/codex/shim-diagnostics.ts +6 -0
  221. package/src/codex/shim-overlay.ts +7 -2
  222. package/src/codex/signed-in-identity.ts +43 -0
  223. package/src/codex/subagent-model-fallback.ts +1 -1
  224. package/src/codex/sync.ts +6 -1
  225. package/src/codex/user-identity.ts +16 -5
  226. package/src/codex/windows-local-appdata.ts +84 -0
  227. package/src/combos/failover.ts +6 -1
  228. package/src/combos/index.ts +1 -0
  229. package/src/combos/resolve.ts +46 -10
  230. package/src/combos/types.ts +15 -0
  231. package/src/config/diagnostics.ts +35 -7
  232. package/src/config/live-reconcile.ts +51 -2
  233. package/src/config/load-degrade.ts +23 -1
  234. package/src/config/opencode-wire-upgrade.ts +54 -0
  235. package/src/config/opencode-zen-upgrade.ts +52 -0
  236. package/src/config/owner-registry.ts +22 -17
  237. package/src/config/paths.ts +10 -3
  238. package/src/config/provider-validation.ts +45 -2
  239. package/src/config/schema/config-schema.ts +39 -0
  240. package/src/config/schema/desktop-compatibility.ts +9 -0
  241. package/src/config/schema/leaf-validators.ts +39 -9
  242. package/src/config/schema/main-account-hard-lock-fallback.ts +26 -0
  243. package/src/config/schema/native-reasoning-retention.ts +26 -0
  244. package/src/config.ts +2 -0
  245. package/src/generated/compatibility-version.json +962 -350
  246. package/src/generated/model-metadata.ts +1 -1
  247. package/src/grok/sync.ts +1 -1
  248. package/src/images/loop.ts +46 -8
  249. package/src/integrations/catalog-refresh.ts +1 -1
  250. package/src/integrations/config-io.ts +20 -2
  251. package/src/integrations/journal.ts +15 -1
  252. package/src/integrations/mutation-plan.ts +2 -0
  253. package/src/integrations/registry.ts +15 -0
  254. package/src/integrations/store.ts +3 -0
  255. package/src/integrations/writer.ts +10 -1
  256. package/src/lib/advisor-activation.ts +16 -0
  257. package/src/lib/background-work.ts +65 -0
  258. package/src/lib/bounded-file-read.ts +58 -0
  259. package/src/lib/bun-path-runtime.d.mts +10 -1
  260. package/src/lib/bun-path-runtime.mjs +62 -3
  261. package/src/lib/codex-restart-contract.ts +15 -0
  262. package/src/lib/desktop-proxy-route.ts +30 -0
  263. package/src/lib/desktop-upstream-tunnel.ts +72 -0
  264. package/src/lib/empty-tool-catalog.ts +62 -0
  265. package/src/lib/errors.ts +26 -3
  266. package/src/lib/gcp-adc.ts +96 -9
  267. package/src/lib/gcp-credential-input.ts +12 -0
  268. package/src/lib/lab-live-route-production.ts +5 -0
  269. package/src/lib/local-internal-call-capability.ts +55 -0
  270. package/src/lib/opaque-proxy-tunnel.ts +217 -0
  271. package/src/lib/package-tree-integrity.ts +2 -2
  272. package/src/lib/redact.ts +2 -2
  273. package/src/lib/socks5-fetch.ts +48 -71
  274. package/src/lib/socks5-handshake.ts +112 -0
  275. package/src/lib/translator-budget.ts +7 -1
  276. package/src/oauth/account-quota-rank.ts +69 -2
  277. package/src/oauth/anthropic-account-refusal.ts +20 -2
  278. package/src/oauth/anthropic-oauth-definitions.ts +3 -1
  279. package/src/oauth/anthropic-routing.ts +1 -21
  280. package/src/oauth/anthropic.ts +38 -7
  281. package/src/oauth/callback-server.ts +27 -1
  282. package/src/oauth/chatgpt-device.ts +1 -1
  283. package/src/oauth/chatgpt-shared.ts +83 -0
  284. package/src/oauth/chatgpt.ts +8 -72
  285. package/src/oauth/dsh.ts +203 -0
  286. package/src/oauth/generic-account-failover.ts +62 -12
  287. package/src/oauth/generic-session-affinity.ts +125 -0
  288. package/src/oauth/index.ts +188 -111
  289. package/src/oauth/kiro-device-login.ts +2 -1
  290. package/src/oauth/kiro.ts +7 -1
  291. package/src/oauth/local-token-detect.ts +21 -1
  292. package/src/oauth/login-cli-errors.ts +44 -0
  293. package/src/oauth/login-cli.ts +69 -7
  294. package/src/oauth/login-flow-state.ts +371 -23
  295. package/src/oauth/meta-muse-errors.ts +41 -0
  296. package/src/oauth/meta-muse-keychain.ts +52 -0
  297. package/src/oauth/meta-muse.ts +51 -84
  298. package/src/oauth/model-discovery-auth.ts +3 -0
  299. package/src/oauth/pool-settings-capability.ts +4 -2
  300. package/src/oauth/refresh-flight-retirement.ts +48 -0
  301. package/src/oauth/session-affinity-key.ts +23 -0
  302. package/src/oauth/store-anthropic-instance.ts +9 -2
  303. package/src/oauth/store.ts +12 -5
  304. package/src/protocols/codecs/chat-ir.ts +467 -0
  305. package/src/protocols/codecs/chat.ts +10 -1
  306. package/src/protocols/codecs/messages-ir.ts +500 -0
  307. package/src/protocols/encoders/adapter-events.ts +5 -4
  308. package/src/protocols/encoders/messages.ts +9 -6
  309. package/src/protocols/features.ts +10 -2
  310. package/src/protocols/path.ts +11 -1
  311. package/src/protocols/plan-snapshot.ts +39 -16
  312. package/src/protocols/plan.ts +9 -1
  313. package/src/protocols/provider-summary.ts +2 -1
  314. package/src/protocols/settings.ts +8 -0
  315. package/src/providers/antigravity-account-roster.ts +102 -0
  316. package/src/providers/antigravity-models.ts +85 -7
  317. package/src/providers/api-key-cooldowns.ts +49 -0
  318. package/src/providers/api-key-resolve.ts +11 -6
  319. package/src/providers/api-key-response-ownership.ts +57 -0
  320. package/src/providers/api-key-selection.ts +31 -6
  321. package/src/providers/api-keys.ts +214 -3
  322. package/src/providers/claude-cli-usage.ts +96 -0
  323. package/src/providers/dsh-account-destination.ts +31 -0
  324. package/src/providers/dsh-account-models.ts +41 -0
  325. package/src/providers/gcp-credential-cleanup.ts +59 -0
  326. package/src/providers/key-failover.ts +54 -50
  327. package/src/providers/key-store.ts +7 -2
  328. package/src/providers/model-rename-fields.ts +5 -0
  329. package/src/providers/model-rename-migration.ts +7 -5
  330. package/src/providers/openai-tiers-destination.ts +11 -2
  331. package/src/providers/openai-tiers.ts +5 -12
  332. package/src/providers/opencode-go-transport.ts +3 -1
  333. package/src/providers/quota/account-cache.ts +6 -5
  334. package/src/providers/quota/account-row.ts +34 -0
  335. package/src/providers/quota/antigravity.ts +28 -7
  336. package/src/providers/quota/dsh-account.ts +70 -0
  337. package/src/providers/quota/vendor-probes-oauth.ts +1 -93
  338. package/src/providers/quota-types.ts +2 -0
  339. package/src/providers/quota.ts +14 -20
  340. package/src/providers/registry/entries-core.ts +44 -14
  341. package/src/providers/registry/entries-extended.ts +19 -0
  342. package/src/providers/registry/types.ts +1 -1
  343. package/src/providers/request-pacing.ts +77 -19
  344. package/src/providers/routed-config.ts +339 -0
  345. package/src/providers/service-tier.ts +2 -1
  346. package/src/quota/window-mapping.ts +5 -2
  347. package/src/responses/anthropic-progress.ts +34 -0
  348. package/src/responses/assistant-replay.ts +35 -0
  349. package/src/responses/compaction-history-framing.ts +65 -0
  350. package/src/responses/compaction.ts +6 -1
  351. package/src/responses/incomplete-reason.ts +31 -0
  352. package/src/responses/parser.ts +78 -22
  353. package/src/responses/reasoning-envelope.ts +4 -0
  354. package/src/responses/reasoning-replay-cache.ts +24 -2
  355. package/src/responses/reasoning-retention.ts +173 -0
  356. package/src/responses/retained-compaction.ts +46 -0
  357. package/src/responses/schema.ts +23 -0
  358. package/src/responses/state.ts +32 -29
  359. package/src/router.ts +8 -321
  360. package/src/routing/health.ts +37 -22
  361. package/src/routing/history/build-file.ts +92 -0
  362. package/src/routing/history/indexer.ts +254 -221
  363. package/src/routing/history/ingest.ts +242 -0
  364. package/src/routing/history/rebuild-job.ts +111 -0
  365. package/src/routing/history/rebuild-protocol.ts +15 -0
  366. package/src/routing/history/rebuild-worker.ts +34 -0
  367. package/src/routing/profile.ts +1 -1
  368. package/src/server/admission-model-scope.ts +21 -1
  369. package/src/server/antigravity-direct-eligibility.ts +208 -0
  370. package/src/server/auth-cors.ts +15 -0
  371. package/src/server/chat-completions.ts +82 -10
  372. package/src/server/chat-native-reasoning.ts +123 -0
  373. package/src/server/chat-native-sse.ts +110 -7
  374. package/src/server/chat-native.ts +76 -17
  375. package/src/server/claude-messages.ts +164 -433
  376. package/src/server/effort-policy.ts +1 -1
  377. package/src/server/images.ts +15 -2
  378. package/src/server/index/desktop-compatibility-startup.ts +56 -0
  379. package/src/server/index/model-alias-id.ts +36 -0
  380. package/src/server/index/optional-listeners.ts +2 -0
  381. package/src/server/index/serve-options.ts +11 -3
  382. package/src/server/index/startup-warnings.ts +11 -0
  383. package/src/server/index/websocket-handler.ts +9 -0
  384. package/src/server/index.ts +14 -11
  385. package/src/server/inference/advisor-diagnostics.ts +31 -0
  386. package/src/server/inference/client-encoder-delivery.ts +6 -5
  387. package/src/server/login-shell-path.ts +146 -0
  388. package/src/server/management/advisor-routes.ts +202 -0
  389. package/src/server/management/agent-settings-routes.ts +22 -4
  390. package/src/server/management/claude-desktop-picker-routes.ts +1 -1
  391. package/src/server/management/combo-routes.ts +176 -50
  392. package/src/server/management/companion-routes.ts +4 -0
  393. package/src/server/management/config-routes.ts +77 -6
  394. package/src/server/management/context.ts +4 -0
  395. package/src/server/management/cursor-integration-routes.ts +1 -1
  396. package/src/server/management/desktop-compatibility-routes.ts +46 -0
  397. package/src/server/management/desktop-compatibility-runtime-routes.ts +46 -0
  398. package/src/server/management/desktop-compatibility-settings-routes.ts +27 -0
  399. package/src/server/management/model-routes.ts +13 -8
  400. package/src/server/management/model-rows.ts +14 -0
  401. package/src/server/management/native-integration-routes.ts +2 -7
  402. package/src/server/management/native-reasoning-retention-routes.ts +41 -0
  403. package/src/server/management/oauth-account-routes.ts +87 -14
  404. package/src/server/management/protocol-settings-patch.ts +1 -0
  405. package/src/server/management/provider-gcp-credential-routes.ts +29 -0
  406. package/src/server/management/provider-key-pacing-routes.ts +31 -0
  407. package/src/server/management/provider-overwrite-carry.ts +7 -0
  408. package/src/server/management/provider-routes.ts +25 -30
  409. package/src/server/management/route-registry.ts +21 -1
  410. package/src/server/management/sibling-guard.ts +1 -0
  411. package/src/server/management-api.ts +9 -1
  412. package/src/server/messages-antigravity-direct.ts +195 -0
  413. package/src/server/messages-native-tool-guard.ts +185 -0
  414. package/src/server/messages-native.ts +106 -22
  415. package/src/server/messages-shared.ts +431 -0
  416. package/src/server/relay.ts +1 -1
  417. package/src/server/request-log-terminal-status.ts +1 -1
  418. package/src/server/request-log.ts +13 -1
  419. package/src/server/responses/account-change-state.ts +8 -2
  420. package/src/server/responses/adapter-continuation.ts +48 -19
  421. package/src/server/responses/adapter-delivery.ts +43 -8
  422. package/src/server/responses/adapter-dispatch.ts +48 -4
  423. package/src/server/responses/advisor-plan-slot.ts +27 -0
  424. package/src/server/responses/advisor-retention.ts +117 -0
  425. package/src/server/responses/advisor-slot.ts +368 -0
  426. package/src/server/responses/code-mode-collab-surface.ts +116 -8
  427. package/src/server/responses/codex-ws-wire.ts +15 -8
  428. package/src/server/responses/compact.ts +303 -125
  429. package/src/server/responses/compaction-recovery.ts +18 -10
  430. package/src/server/responses/compaction-retention.ts +61 -0
  431. package/src/server/responses/context-overflow.ts +11 -6
  432. package/src/server/responses/core-auth.ts +6 -0
  433. package/src/server/responses/core-codex-account.ts +11 -1
  434. package/src/server/responses/core-combo-failure.ts +12 -1
  435. package/src/server/responses/core-combo.ts +141 -36
  436. package/src/server/responses/core-errors.ts +3 -3
  437. package/src/server/responses/core-lifetime.ts +7 -2
  438. package/src/server/responses/core-normalize.ts +11 -0
  439. package/src/server/responses/core-opaque-recovery.ts +35 -0
  440. package/src/server/responses/core-options.ts +51 -0
  441. package/src/server/responses/core-pipeline.ts +141 -0
  442. package/src/server/responses/core-replay.ts +25 -6
  443. package/src/server/responses/core.ts +3 -116
  444. package/src/server/responses/fetch-helpers.ts +73 -19
  445. package/src/server/responses/main-hard-lock-routing.ts +109 -0
  446. package/src/server/responses/native-response-control.ts +4 -2
  447. package/src/server/responses/passthrough-delivery.ts +19 -11
  448. package/src/server/responses/passthrough-dispatch.ts +29 -16
  449. package/src/server/responses/request-prepare.ts +144 -17
  450. package/src/server/responses/request-sidecar-auth.ts +2 -2
  451. package/src/server/responses/request-transport.ts +120 -27
  452. package/src/server/responses/response-effects.ts +1 -0
  453. package/src/server/responses/run-turn-execution.ts +166 -38
  454. package/src/server/responses/sidecar-execution.ts +98 -5
  455. package/src/server/responses/terminal-guard.ts +4 -17
  456. package/src/server/responses-undeclared-tool-guard.ts +30 -9
  457. package/src/server/startup-action-control.ts +16 -2
  458. package/src/server/startup-health-cache.ts +1 -0
  459. package/src/service/auth-preflight.ts +71 -0
  460. package/src/service/cli.ts +4 -2
  461. package/src/service/definition.ts +97 -0
  462. package/src/service/desktop-startup.ts +14 -0
  463. package/src/service/guards.ts +1 -61
  464. package/src/service/health-sentinel-linux.ts +112 -0
  465. package/src/service/health-sentinel-main.ts +99 -61
  466. package/src/service/health-sentinel-probe.ts +24 -7
  467. package/src/service/health.ts +5 -89
  468. package/src/service/launchd.ts +27 -7
  469. package/src/service/logging.ts +135 -0
  470. package/src/service/repair.ts +2 -1
  471. package/src/service/state.ts +7 -8
  472. package/src/service/systemd.ts +1 -1
  473. package/src/service/windows-guarded-manager.ts +2 -1
  474. package/src/service/windows-ops.ts +1 -1
  475. package/src/service/windows-scheduler.ts +2 -7
  476. package/src/service/windows-taskxml.ts +2 -2
  477. package/src/service/windows-wscript.ts +14 -0
  478. package/src/service.ts +4 -2
  479. package/src/sidecar/auth.ts +2 -0
  480. package/src/tray/windows-tray.ps1 +43 -24
  481. package/src/types/config.ts +124 -6
  482. package/src/types/opencode-go.ts +61 -0
  483. package/src/types/opencode-zen.ts +29 -0
  484. package/src/types/provider.ts +39 -6
  485. package/src/types/request.ts +38 -2
  486. package/src/types/tools.ts +2 -0
  487. package/src/types/wire.ts +29 -37
  488. package/src/types.ts +1 -0
  489. package/src/update/async-check.ts +1 -1
  490. package/src/update/badge.ts +2 -2
  491. package/src/update/index.ts +88 -15
  492. package/src/update/job-supervised-restart.ts +107 -0
  493. package/src/update/job.ts +32 -32
  494. package/src/update/notify.ts +1 -1
  495. package/src/update/npm-invocation.mjs +12 -2
  496. package/src/update/refresh-scheduler.ts +2 -2
  497. package/src/update/supervised-recovery.d.mts +27 -0
  498. package/src/update/supervised-recovery.mjs +157 -0
  499. package/src/usage/cache-diagnostic.ts +2 -0
  500. package/src/usage/cost.ts +48 -12
  501. package/src/usage/expected-prices.ts +15 -0
  502. package/src/usage/ledger-retention.ts +2 -1
  503. package/src/usage/ledger-scanner.ts +6 -5
  504. package/src/usage/log.ts +17 -8
  505. package/src/usage/summary.ts +22 -9
  506. package/src/usage/user-cost-overlays.ts +14 -19
  507. package/src/usage/user-cost-validation.ts +38 -0
  508. package/src/vision/eligibility.ts +13 -0
  509. package/src/web-search/gemini-executor.ts +2 -2
  510. package/src/web-search/loop.ts +55 -5
  511. package/src/web-search/progress-stream.ts +4 -1
  512. package/src/web-search/run-turn-loop.ts +9 -1
  513. package/assets/sponsors/packycode.png +0 -0
  514. package/gui/dist/assets/App-CSJvmjNs.css +0 -1
  515. package/gui/dist/assets/App-CZtqiGcw.js +0 -56
  516. package/gui/dist/assets/index-BB6uK6tU.css +0 -1
  517. package/gui/dist/assets/index-CTm4l-HQ.js +0 -94
  518. package/gui/dist/assets/quota-summary-BbEeRfPY.js +0 -1
@@ -61,7 +61,9 @@ import {
61
61
  type UpstreamSendRecovery,
62
62
  UPSTREAM_RESET_REPLAY_REFUSED_CODE,
63
63
  } from "../lib/upstream-retry";
64
+ import { distributedKeyPhysicalFetch, distributedKeyResponseOwner, recordDistributedResponseFailure } from "../providers/api-key-response-ownership";
64
65
  import { providerApiKeySelectionIsCurrent, resolveCurrentProviderApiKeyTransport } from "../providers/api-key-selection";
66
+ import { RequestPacingQueueOverloadError } from "../providers/request-pacing";
65
67
  import {
66
68
  hasKeyPoolFailover,
67
69
  rateLimitRetryDelayMs,
@@ -82,6 +84,7 @@ import { preservesPhysicalComboProvider, resolveComboId } from "../combos";
82
84
  import { captureRouteStaticPolicy, routedProviderConfig, routeModel, type RouteResult } from "../router";
83
85
  import { POLICY_NAMESPACE, resolvePolicyProfileId } from "../routing/profile";
84
86
  import type { AnthropicClientIdentity } from "../adapters/anthropic/client-identity";
87
+ import { logDroppedAnthropicBetas } from "../adapters/anthropic/beta-allowlist";
85
88
  import type { OcxConfig, OcxProviderConfig, OcxUsage } from "../types";
86
89
  import { resolveWireProtocolOverride } from "./adapter-resolve";
87
90
  import {
@@ -90,12 +93,14 @@ import {
90
93
  resolvePassthroughBodyGuard,
91
94
  sanitizePassthroughToolCallIds,
92
95
  tapAnthropicSseForLog,
93
- } from "./claude-messages";
96
+ } from "./messages-shared";
94
97
  import { beginInferenceAttempt } from "./inference/attempt";
95
98
  import { createFinalRequestLog, type FinalRequestLogMeta } from "./inference/final-log";
96
99
  import { registerTurn, unregisterTurn } from "./lifecycle";
97
100
  import { nativeMessagesDeclineReason, type NativeMessagesSelector } from "./messages-native-eligibility";
98
101
  import { messagesSecondaryInstanceUnavailable } from "./messages-native-selector";
102
+ import { guardNativeMessagesEmptyToolCatalog, nativeMessagesClientToolName, nativeMessagesInlineToolNames } from "./messages-native-tool-guard";
103
+ import { UNDECLARED_TOOL_CALL_ERROR_CODE, undeclaredToolCallMessage } from "./responses-undeclared-tool-guard";
99
104
  import {
100
105
  nativeOAuthBindingIsCurrent,
101
106
  NativeOAuthSelectionChangedError,
@@ -314,6 +319,8 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
314
319
  const { req, config, logCtx, logIds, route, body, requestedModel, translatorBudget } = options;
315
320
  const nativeInstance = configuredAnthropicInstance(config, route.providerName);
316
321
  const requestedStream = body.stream === true;
322
+ const clientDeclaredEmptyToolCatalog = Array.isArray(body.tools) && body.tools.length === 0;
323
+ const declaredInlineTools = clientDeclaredEmptyToolCatalog ? nativeMessagesInlineToolNames(body) : undefined;
317
324
  logCtx.inboundProtocol = "messages";
318
325
  logCtx.model = route.modelId;
319
326
  logCtx.provider = route.providerName;
@@ -435,8 +442,16 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
435
442
  }
436
443
  } else {
437
444
  // Same pre-dispatch key preference every direct send path applies (see chat-native.ts).
438
- const proactiveKeyProvider = selectProactiveApiKeyTransport(config, route.providerName, route.provider);
439
- if (proactiveKeyProvider) route.provider = proactiveKeyProvider;
445
+ try {
446
+ const proactiveKeyProvider = selectProactiveApiKeyTransport(config, route.providerName, route.provider);
447
+ if (proactiveKeyProvider) route.provider = proactiveKeyProvider;
448
+ } catch (error) {
449
+ cleanupAbort(); upstream.abort();
450
+ if (!(error instanceof RequestPacingQueueOverloadError)) throw error;
451
+ const refusal = fail(429, error.message, "rate_limit_error");
452
+ refusal.headers.set("Retry-After", String(error.retryAfterSeconds));
453
+ return refusal;
454
+ }
440
455
  }
441
456
  let activeProvider: OcxProviderConfig = oauthBinding ? oauthProvider(oauthBinding) : route.provider;
442
457
  stampApiKeyAccountLabel(logCtx, route.providerName, activeProvider);
@@ -469,7 +484,10 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
469
484
  clientIdentity: options.clientIdentity,
470
485
  });
471
486
  if (built.strippedOpaqueState && rejectUnrepresentable) throw new NativeOpaqueStateRefusal();
472
- if (built.droppedBetas) addProtocolEntryReason(logCtx, "anthropic-beta-dropped");
487
+ if (built.droppedBetas) {
488
+ addProtocolEntryReason(logCtx, "anthropic-beta-dropped");
489
+ logDroppedAnthropicBetas({ droppedNames: built.droppedBetaNames, droppedUnrecognized: built.droppedUnrecognizedBetas });
490
+ }
473
491
  if (built.strippedOpaqueState) addProtocolEntryReason(logCtx, "opaque-state-stripped");
474
492
  return built;
475
493
  };
@@ -517,6 +535,15 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
517
535
  && nativeMessagesDeclineReason({ ...route, provider: routed }, body, config, selector) === undefined;
518
536
  };
519
537
 
538
+ // Keep the actual failed wire identity if a later recovery is refused before sending.
539
+ // A 429 remains eligible for explicit same-key retries until that ladder is finished.
540
+ let pendingDistributedFailure: (() => void) | undefined;
541
+ let distributedResponseOwnsKey = true;
542
+ const settleDistributedFailure = () => {
543
+ const record = pendingDistributedFailure;
544
+ pendingDistributedFailure = undefined;
545
+ record?.();
546
+ };
520
547
  const send = async (recovery?: "rate-limit-429" | "oauth-401" | "oauth-account-403" | "key-429" | "key-401"): Promise<Response> => {
521
548
  const remaining = remainingTransientSends();
522
549
  if (requestTransientPolicy && remaining <= 0) {
@@ -534,7 +561,7 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
534
561
  providerFetch(activeProvider, undefined, {
535
562
  providerName: route.providerName,
536
563
  modelId: route.modelId,
537
- dispatchOverride: async (_input, init, execute) => {
564
+ dispatchOverride: async (_input, init, execute, reacquirePacing) => {
538
565
  if (oauthBinding) {
539
566
  if (!nativeOAuthRouteIsCurrent(oauthBinding)) throw new NativeOAuthSelectionChangedError();
540
567
  // The OAuth twin of the key check below: re-resolve through the same selection
@@ -551,12 +578,25 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
551
578
  rebuildFor(oauthProvider(oauthBinding));
552
579
  logCtx.provider = formatAnthropicProviderForLog(route.providerName, oauthBinding.snapshot.accountId, config);
553
580
  }
554
- } else if (!providerApiKeySelectionIsCurrent(config, route.providerName, activeProvider)) {
555
- const current = resolveCurrentProviderApiKeyTransport(config, route.providerName, activeProvider);
556
- if (!current || nativeMessagesDeclineReason({ ...route, provider: current }, body, config, selector) !== undefined) {
557
- throw new Error("Provider key selection is no longer available for native Messages");
581
+ } else {
582
+ for (let attempt = 0; !providerApiKeySelectionIsCurrent(config, route.providerName, activeProvider); attempt++) {
583
+ if (attempt >= 3) throw new Error("Provider key selection changed repeatedly before native Messages dispatch");
584
+ let current = resolveCurrentProviderApiKeyTransport(config, route.providerName, activeProvider);
585
+ if (!current && activeProvider.requestPacing?.enabled
586
+ && (activeProvider.requestPacing.keys || activeProvider.requestPacing.keySelection === "round-robin")) {
587
+ const fresh = resolveCurrentProviderApiKeyTransport(config, route.providerName, { ...activeProvider, _apiKeyAttempt: undefined });
588
+ if (fresh) current = selectProactiveApiKeyTransport(config, route.providerName, fresh) ?? fresh;
589
+ }
590
+ if (!current || nativeMessagesDeclineReason({ ...route, provider: current }, body, config, selector) !== undefined) {
591
+ throw new Error("Provider key selection is no longer available for native Messages");
592
+ }
593
+ rebuildFor(current);
594
+ if (current.requestPacing?.enabled
595
+ && (current.requestPacing.keys || current.requestPacing.keySelection === "round-robin")) {
596
+ if (!reacquirePacing) throw new Error("Refreshed native Messages dispatch requires pacing readmission");
597
+ await reacquirePacing(current, route.modelId);
598
+ }
558
599
  }
559
- rebuildFor(current);
560
600
  }
561
601
  // The retry closure may hold a pre-reselection request: send the current one whole.
562
602
  const wire = activeRequest;
@@ -575,6 +615,7 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
575
615
  }
576
616
  const releaseFamily = snapshot && oauthBinding ? anthropicModelQuotaFor(oauthBinding.instance).claimAnthropicFamilyRevalidation(snapshot.accountId, route.modelId) : () => {};
577
617
  if (!releaseFamily) throw new AnthropicAccountCooldownError(1);
618
+ const selection = activeProvider._apiKeyAttempt;
578
619
  let dispatched: Response;
579
620
  const spendReport = createPhysicalSendReporter(physicalBudget, () => ({
580
621
  poolId: logCtx.spendPoolId ?? route.providerName, identityId: logCtx.accountLogLabel,
@@ -595,7 +636,9 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
595
636
  if (snapshot && !sendOwner) throw new NativeOAuthSelectionChangedError();
596
637
  physicalSendsUsed++;
597
638
  dispatched = await sendWithConnectionPolicy(
598
- anthropicBillingPhysicalFetch((activeProvider as OcxProviderTransport).fetch ?? execute, route.providerName, activeProvider),
639
+ distributedKeyPhysicalFetch(
640
+ anthropicBillingPhysicalFetch((activeProvider as OcxProviderTransport).fetch ?? execute, route.providerName, activeProvider),
641
+ route.providerName, activeProvider, wire.url, activeProvider.apiKeyTransport === "bearer" ? "authorization" : "x-api-key"),
599
642
  wire.url,
600
643
  applyUpstreamRecoveryInit({ ...init, method: "POST", headers, body: wire.body }, transportRecovery),
601
644
  { providerName: route.providerName, provider: activeProvider },
@@ -619,6 +662,14 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
619
662
  }
620
663
  } catch { /* Passive observation must not fail the response. */ }
621
664
  }
665
+ const ownsDistributedKey = !selection?.distributed
666
+ || distributedKeyResponseOwner(dispatched, config, route.providerName) !== null;
667
+ distributedResponseOwnsKey = ownsDistributedKey;
668
+ const failureStatus = dispatched.status;
669
+ pendingDistributedFailure = selection?.distributed && ownsDistributedKey && (failureStatus === 401 || failureStatus === 429)
670
+ && !isNonReplayableResponse(dispatched)
671
+ ? () => { recordDistributedResponseFailure(dispatched, config, route.providerName, req.signal); }
672
+ : undefined;
622
673
  if (!dispatched.ok) await recordKeyAttemptFailure(logCtx, dispatched, init.signal ?? upstream.signal);
623
674
  return dispatched;
624
675
  },
@@ -643,25 +694,28 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
643
694
  let response: Response;
644
695
  try {
645
696
  response = await send();
646
- const retryPolicy = oauthBinding ? undefined : rateLimitRetryPolicyFor(activeProvider);
697
+ let retryPolicy: ReturnType<typeof rateLimitRetryPolicyFor> | undefined;
647
698
  let retries = 0;
648
699
  let billingRecoveryActive = false;
649
700
  const keySendAvailable = () => transientSendAvailable()
650
701
  && (!billingRecoveryActive || Math.max(physicalSendsUsed, physicalBudget.used) < physicalBudget.policy.maxTotalModelSends);
651
- for (;;) {
702
+ const recoveryPasses = activeProvider._apiKeyAttempt?.distributed ? activeProvider.apiKeyPool?.length ?? 1 : 1;
703
+ for (let pass = 0; ; pass++) {
652
704
  const priorResponse = response;
653
705
  // A credential-scoped 401 on a static key pool says nothing about the sibling keys.
654
- while (response.status === 401 && hasKeyPoolFailover(activeProvider) && keySendAvailable()) {
706
+ while (response.status === 401 && distributedResponseOwnsKey && hasKeyPoolFailover(activeProvider) && keySendAvailable()) {
655
707
  const rotated = rotateProviderTransportOn401(config, route.providerName, activeProvider, {
656
708
  now: Date.now(),
657
709
  attemptedKey: activeProvider.apiKey,
710
+ attemptedSelection: activeProvider._apiKeyAttempt,
658
711
  });
712
+ pendingDistributedFailure = undefined; // Rotation already records this physical failure.
659
713
  if (!rotated) break;
660
714
  discard(response);
661
715
  rebuildFor(rotated);
662
716
  response = await send("key-401");
663
717
  }
664
- while ((response.status === 400 || response.status === 402) && hasKeyPoolFailover(activeProvider)) {
718
+ while ((response.status === 400 || response.status === 402) && distributedResponseOwnsKey && hasKeyPoolFailover(activeProvider)) {
665
719
  const rotated = await rotateAnthropicBillingKeyOnResponse(response, config, route.providerName, activeProvider, { signal: upstream.signal });
666
720
  if (!rotated) break;
667
721
  billingRecoveryActive = true;
@@ -670,9 +724,11 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
670
724
  rebuildFor(rotated);
671
725
  response = await send("key-401");
672
726
  }
727
+ if (pass === 0) retryPolicy = oauthBinding ? undefined : rateLimitRetryPolicyFor(activeProvider);
673
728
  // A refusal this proxy synthesized for a reset replay is not a provider rate limit.
674
729
  while (
675
730
  response.status === 429
731
+ && distributedResponseOwnsKey
676
732
  && !isNonReplayableResponse(response)
677
733
  && retryPolicy
678
734
  && retries < retryPolicy.attempts
@@ -687,13 +743,14 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
687
743
  if (upstream.signal.aborted) throw upstream.signal.reason;
688
744
  response = await send("rate-limit-429");
689
745
  }
690
- while (response.status === 429 && !isNonReplayableResponse(response) && hasKeyPoolFailover(activeProvider)) {
746
+ while (response.status === 429 && distributedResponseOwnsKey && !isNonReplayableResponse(response) && hasKeyPoolFailover(activeProvider)) {
691
747
  const rotated = rotateProviderTransportOn429(config, route.providerName, activeProvider, {
692
748
  retryAfter: response.headers.get("retry-after"),
693
749
  now: Date.now(),
694
750
  attemptedKey: activeProvider.apiKey,
695
751
  attemptedSelection: activeProvider._apiKeyAttempt,
696
752
  });
753
+ pendingDistributedFailure = undefined; // Rotation already records this physical failure.
697
754
  if (!rotated) break;
698
755
  // Rotation already recorded the cooldown; keep the terminal 429 when no send remains.
699
756
  if (!keySendAvailable()) break;
@@ -701,13 +758,17 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
701
758
  rebuildFor(rotated);
702
759
  response = await send("key-429");
703
760
  }
704
- // A sibling's next refusal may change class; the same counters survive that transition.
705
- if (response !== priorResponse && (
761
+ if (response === priorResponse || isNonReplayableResponse(response) || !keySendAvailable()) break;
762
+ // Billing class transitions share the physical-send ceiling; distributed-only
763
+ // transitions additionally retain their original bounded pool-pass allowance.
764
+ if (distributedResponseOwnsKey && (
706
765
  (billingRecoveryActive && [401, 429].includes(response.status))
707
766
  || (activeProvider.adapter === "anthropic" && hasKeyPoolFailover(activeProvider) && [400, 402].includes(response.status))
708
767
  )) continue;
709
- break;
768
+ if (!activeProvider._apiKeyAttempt?.distributed || !distributedResponseOwnsKey
769
+ || (response.status !== 401 && response.status !== 429) || pass + 1 >= recoveryPasses) break;
710
770
  }
771
+ settleDistributedFailure();
711
772
  const oauthRetryKey = {};
712
773
  const triedAccountIds = new Set<string>();
713
774
  let oauthFailovers = 0;
@@ -745,7 +806,13 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
745
806
  cleanupAbort();
746
807
  upstream.abort();
747
808
  if (req.signal.aborted) return fail(499, "Client cancelled request", "api_error");
809
+ settleDistributedFailure();
748
810
  const sendError = error instanceof UpstreamRetryEvidenceError ? error.cause : error;
811
+ if (sendError instanceof RequestPacingQueueOverloadError) {
812
+ const refusal = fail(429, sendError.message, "rate_limit_error");
813
+ refusal.headers.set("Retry-After", String(sendError.retryAfterSeconds));
814
+ return refusal;
815
+ }
749
816
  if (sendError instanceof SendBudgetExhaustedError) return fail(429, sendError.message, "send_budget_exhausted", "send_budget_exhausted");
750
817
  if (sendError instanceof NativeMessagesSpendRefusal) {
751
818
  const refusal = workflowRefusalResponse("workflow-spend-exhausted", logCtx);
@@ -790,15 +857,22 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
790
857
  const renamed = activeRequest.oauthToolNames
791
858
  ? restoreOAuthToolNamesInSse(observed, activeRequest.oauthToolNames, translatorBudget)
792
859
  : observed;
793
- const source = echoRequestedModel(renamed, requestedModel);
860
+ const echoed = echoRequestedModel(renamed, requestedModel);
861
+ let toolRefusal: string | undefined;
862
+ const source = clientDeclaredEmptyToolCatalog
863
+ ? guardNativeMessagesEmptyToolCatalog(echoed, translatorBudget, message => {
864
+ toolRefusal = message;
865
+ logCtx.errorCode = UNDECLARED_TOOL_CALL_ERROR_CODE;
866
+ }, declaredInlineTools)
867
+ : echoed;
794
868
  if (requestedStream) {
795
869
  transferTurnToStream();
796
870
  const relayed = tapAnthropicSseForLog(source, logCtx, (status, meta) => {
797
871
  try {
798
872
  cleanupAbort();
799
873
  bindUsage(logCtx.usage);
800
- finishLog(status, undefined, meta);
801
- if (meta.closeReason !== "terminal") upstream.abort();
874
+ finishLog(toolRefusal ? 502 : status, toolRefusal, toolRefusal ? { ...meta, terminalStatus: "failed" } : meta);
875
+ if (toolRefusal || meta.closeReason !== "terminal") upstream.abort();
802
876
  } finally {
803
877
  releaseStreamTurn();
804
878
  }
@@ -829,6 +903,11 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
829
903
  if (message.type === "error") {
830
904
  const error = isRec(message.error) ? message.error : {};
831
905
  const text = typeof error.message === "string" ? error.message : "upstream stream failed";
906
+ if (toolRefusal) {
907
+ upstream.abort();
908
+ finishLog(502, toolRefusal, { closeReason: "terminal", terminalStatus: "failed" });
909
+ return fail(502, toolRefusal, "api_error", UNDECLARED_TOOL_CALL_ERROR_CODE);
910
+ }
832
911
  // The tap's own verdict (a reset, a stall, the byte cap) closes this row with the same meta
833
912
  // as the streaming lane's row; a plain upstream error event keeps the non_stream row.
834
913
  const tapMeta = tapState.meta;
@@ -880,6 +959,11 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
880
959
  const message = activeRequest.oauthToolNames
881
960
  ? restoreOAuthToolNamesInMessage(parsedMessage, activeRequest.oauthToolNames)
882
961
  : parsedMessage;
962
+ const undeclaredTool = clientDeclaredEmptyToolCatalog ? nativeMessagesClientToolName(message, declaredInlineTools) : undefined;
963
+ if (undeclaredTool !== undefined) {
964
+ logCtx.errorCode = UNDECLARED_TOOL_CALL_ERROR_CODE;
965
+ return fail(502, undeclaredToolCallMessage(undeclaredTool), "api_error", UNDECLARED_TOOL_CALL_ERROR_CODE);
966
+ }
883
967
  bindUsage(anthropicUsageToOcx(isRec(message.usage) ? message.usage : undefined));
884
968
  if (logIds) recordFirstOutput(logCtx, logIds.start);
885
969
  try {