@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
@@ -2,6 +2,7 @@ import type { OcxUsage } from "../../types";
2
2
  import type { AgentServerMessage, McpArgs, ToolCall } from "./gen/agent_pb";
3
3
  import { decodeCursorArgsMap } from "./arg-codec";
4
4
  import { normalizeArgKeys } from "./arg-normalize";
5
+ import { canonicalCursorFreeformArgs } from "./freeform-args";
5
6
  import {
6
7
  CODEX_APPLY_PATCH_TOOL,
7
8
  CURSOR_MULTI_EDIT_TOOL,
@@ -334,9 +335,20 @@ function toolSchemaForWireName(state: CursorProtobufEventState, toolName: string
334
335
  return resolveShellBridgeAliasKey(toolName, alias => state.toolSchemas!.get(alias));
335
336
  }
336
337
 
337
- function decodeMcpArgsNormalized(args: McpArgs | undefined, state: CursorProtobufEventState): string {
338
- const decoded = decodeCursorArgsMap(args?.args);
338
+ function isFreeformCall(state: CursorProtobufEventState, responsesName: string | undefined): boolean {
339
+ return responsesName !== undefined && state.freeformToolNames?.has(responsesName) === true;
340
+ }
341
+
342
+ function decodeMcpArgsNormalized(
343
+ args: McpArgs | undefined,
344
+ state: CursorProtobufEventState,
345
+ openResponsesName?: string,
346
+ ): string {
339
347
  const toolName = mcpWireNameFromArgs(args);
348
+ const responsesName = toolName
349
+ ? responsesToolNameFromCursorWire(toolName, state.cursorToolNameMap)
350
+ : openResponsesName;
351
+ const decoded = decodeCursorArgsMap(args?.args, { preserveStrings: isFreeformCall(state, responsesName) });
340
352
  const schema = toolSchemaForWireName(state, toolName);
341
353
  if (schema) return JSON.stringify(normalizeArgKeys(decoded, schema));
342
354
  return JSON.stringify(decoded);
@@ -381,8 +393,13 @@ function normalizeJsonText(text: string, toolName: string | undefined, state: Cu
381
393
  * preserved verbatim so the bridge can reject malformed or truncated JSON instead of silently
382
394
  * converting it to `{}`. A genuinely empty buffer remains the no-argument case.
383
395
  */
384
- function resolveCompletedArgs(buffered: string, args: McpArgs | undefined, state: CursorProtobufEventState): string {
385
- if (hasMcpArgBytes(args)) return decodeMcpArgsNormalized(args, state);
396
+ function resolveCompletedArgs(
397
+ buffered: string,
398
+ args: McpArgs | undefined,
399
+ state: CursorProtobufEventState,
400
+ openResponsesName?: string,
401
+ ): string {
402
+ if (hasMcpArgBytes(args)) return decodeMcpArgsNormalized(args, state, openResponsesName);
386
403
  const name = mcpWireNameFromArgs(args);
387
404
  if (isCompleteJson(buffered)) return normalizeJsonText(buffered, name, state);
388
405
  return buffered;
@@ -1092,7 +1109,7 @@ export function mapSyntheticMcpExecToToolEvents(
1092
1109
  const out: CursorServerMessage[] = [...recordToolCall(options.state, callId, cursorWireName)];
1093
1110
  if (out.some(event => event.type === "error")) return out;
1094
1111
  const open = options.state.openToolCalls.get(callId);
1095
- const finalArgs = resolveCompletedArgs(open?.args ?? "", args, options.state);
1112
+ const finalArgs = resolveCompletedArgs(open?.args ?? "", args, options.state, open?.name);
1096
1113
  out.push(...commitToolCall(options.state, callId, finalArgs));
1097
1114
  return out;
1098
1115
  }
@@ -1167,23 +1184,16 @@ function discardBufferedTextToolCalls(state: CursorProtobufEventState): void {
1167
1184
  * recorded in `openToolCalls`. Because each completion emits a whole non-interleaved unit, the bridge
1168
1185
  * (which tracks a single current tool call) serializes parallel Cursor calls correctly.
1169
1186
  */
1170
- function cursorFreeformWrapperValid(args: string): boolean {
1171
- try {
1172
- const parsed = JSON.parse(args) as unknown;
1173
- return !!parsed
1174
- && typeof parsed === "object"
1175
- && !Array.isArray(parsed)
1176
- && typeof (parsed as Record<string, unknown>).input === "string";
1177
- } catch {
1178
- return false;
1179
- }
1187
+ /** True when the args already carry a body this call can commit, canonical or repairable (#7049). */
1188
+ function cursorFreeformArgsCommittable(args: string, toolName: string): boolean {
1189
+ return canonicalCursorFreeformArgs(args, toolName).ok;
1180
1190
  }
1181
1191
 
1182
- function dropInvalidFreeformCall(state: CursorProtobufEventState, callId: string, toolName: string): CursorServerMessage[] {
1192
+ function dropInvalidFreeformCall(state: CursorProtobufEventState, callId: string, toolName: string, reason: string): CursorServerMessage[] {
1183
1193
  state.openToolCalls.delete(callId);
1184
1194
  state.translatorBudget?.closeCall(callId);
1185
1195
  state.completedToolCalls.add(callId);
1186
- return [{ type: "error", message: `${toolName} call had invalid freeform arguments; expected {input:string}` }];
1196
+ return [{ type: "error", message: `${toolName} call had invalid freeform arguments; expected {input:string} (${reason})` }];
1187
1197
  }
1188
1198
 
1189
1199
  function dropShellBridgeCall(state: CursorProtobufEventState, callId: string, toolName: string): CursorServerMessage[] {
@@ -1202,11 +1212,14 @@ function dropStructuredEditCall(state: CursorProtobufEventState, callId: string,
1202
1212
  return [{ type: "text", text: `\n${toolName} call was not converted to apply_patch: ${reason}` }];
1203
1213
  }
1204
1214
 
1205
- function commitToolCall(state: CursorProtobufEventState, callId: string, finalArgs: string): CursorServerMessage[] {
1215
+ function commitToolCall(state: CursorProtobufEventState, callId: string, committedArgs: string): CursorServerMessage[] {
1206
1216
  const open = state.openToolCalls.get(callId);
1207
1217
  if (!open) return [];
1208
- if (state.freeformToolNames?.has(open.name) && !cursorFreeformWrapperValid(finalArgs)) {
1209
- return dropInvalidFreeformCall(state, callId, open.name);
1218
+ let finalArgs = committedArgs;
1219
+ if (isFreeformCall(state, open.name)) {
1220
+ const freeform = canonicalCursorFreeformArgs(finalArgs, open.name);
1221
+ if (!freeform.ok) return dropInvalidFreeformCall(state, callId, open.name, freeform.reason);
1222
+ finalArgs = freeform.args;
1210
1223
  }
1211
1224
  const schema = toolSchemaForWireName(state, open.name);
1212
1225
  if (!cursorShellBridgeArgsValid(finalArgs, open.name, schema)) {
@@ -1386,7 +1399,7 @@ export function mapCursorProtobufServerMessage(
1386
1399
  && (
1387
1400
  (name !== undefined && openBeforeStart.args.length === 0)
1388
1401
  || (state.freeformToolNames?.has(openBeforeStart.name) === true
1389
- && !cursorFreeformWrapperValid(openBeforeStart.args)
1402
+ && !cursorFreeformArgsCommittable(openBeforeStart.args, openBeforeStart.name)
1390
1403
  )
1391
1404
  )
1392
1405
  ) {
@@ -1410,13 +1423,13 @@ export function mapCursorProtobufServerMessage(
1410
1423
  if (
1411
1424
  !openBeforeStart && open && !hasMcpArgBytes(args)
1412
1425
  && state.freeformToolNames?.has(open.name) === true
1413
- && !cursorFreeformWrapperValid(open.args)
1426
+ && !cursorFreeformArgsCommittable(open.args, open.name)
1414
1427
  ) {
1415
1428
  open.awaitingNativeArgs = true;
1416
1429
  return [];
1417
1430
  }
1418
1431
  if (open) {
1419
- const finalArgs = resolveCompletedArgs(open.args, args, state);
1432
+ const finalArgs = resolveCompletedArgs(open.args, args, state, open.name);
1420
1433
  out.push(...commitToolCall(state, update.value.callId, finalArgs));
1421
1434
  }
1422
1435
  return out;
@@ -0,0 +1,97 @@
1
+ import type { IncomingMeta, ProviderAdapter } from "./base";
2
+ import { createAnthropicAdapter } from "./anthropic";
3
+ import type { AdapterFactoryContext } from "./registry";
4
+ import type { OcxParsedRequest, OcxProviderConfig } from "../types";
5
+ import { resolveDshAccountMessagesUrl } from "../providers/dsh-account-destination";
6
+
7
+ export { DSH_ACCOUNT_DEFAULT_MESSAGES_URL, resolveDshAccountMessagesUrl } from "../providers/dsh-account-destination";
8
+
9
+ export const DSH_ACCOUNT_RESERVED_HEADERS = new Set([
10
+ "x-dsh-auth-token",
11
+ "anthropic-version",
12
+ "authorization",
13
+ "x-api-key",
14
+ "host",
15
+ ]);
16
+
17
+ export function createDshAccountAdapter(
18
+ provider: OcxProviderConfig,
19
+ _context?: AdapterFactoryContext,
20
+ ): ProviderAdapter {
21
+ // Use key authMode internally so that createAnthropicAdapter doesn't inject Claude Code headers/prompt.
22
+ const baseAdapter = createAnthropicAdapter({
23
+ ...provider,
24
+ authMode: "key",
25
+ }, "none");
26
+
27
+ return {
28
+ ...baseAdapter,
29
+ name: "dsh-account",
30
+
31
+ formatErrorBody(status: number, headers: Headers, payloadText: string): string {
32
+ if (status === 401) {
33
+ return "DeepSeek Harness account authentication failed (401 / ACCOUNT_TOKEN_INVALID). Please sign in to DeepSeek Harness Desktop and re-import.";
34
+ }
35
+ return baseAdapter.formatErrorBody?.(status, headers, payloadText) ?? payloadText;
36
+ },
37
+
38
+ async buildRequest(parsed: OcxParsedRequest, incoming: IncomingMeta) {
39
+ const token = provider.apiKey?.trim();
40
+ if (!token) {
41
+ throw new Error("DeepSeek Harness account token missing — import your account in Providers > DeepSeek Account (DSH)");
42
+ }
43
+
44
+ // Fail-closed if custom provider configuration attempts to set any reserved header
45
+ if (provider.headers) {
46
+ for (const key of Object.keys(provider.headers)) {
47
+ if (DSH_ACCOUNT_RESERVED_HEADERS.has(key.toLowerCase())) {
48
+ throw new Error(`Reserved header "${key}" cannot be overridden in dsh-account provider configuration`);
49
+ }
50
+ }
51
+ }
52
+
53
+ const req = await baseAdapter.buildRequest(parsed, incoming);
54
+ const url = resolveDshAccountMessagesUrl(provider.baseUrl);
55
+
56
+ const headers: Record<string, string> = { ...req.headers };
57
+
58
+ // Apply custom provider headers strictly before authoritative authentication headers
59
+ if (provider.headers) {
60
+ for (const [key, value] of Object.entries(provider.headers)) {
61
+ if (!DSH_ACCOUNT_RESERVED_HEADERS.has(key.toLowerCase()) && typeof value === "string") {
62
+ headers[key] = value;
63
+ }
64
+ }
65
+ }
66
+
67
+ // Authoritative cleanup: strip any API key or Claude headers
68
+ for (const key of Object.keys(headers)) {
69
+ const lower = key.toLowerCase();
70
+ if (
71
+ lower === "authorization"
72
+ || lower === "x-api-key"
73
+ || lower === "x-dsh-auth-token"
74
+ || lower === "anthropic-version"
75
+ || lower === "anthropic-beta"
76
+ || lower === "x-claude-code-session-id"
77
+ || lower === "x-client-request-id"
78
+ ) {
79
+ delete headers[key];
80
+ }
81
+ }
82
+
83
+ // Set authoritative DeepSeek Harness Account headers strictly at the end
84
+ headers["x-dsh-auth-token"] = token;
85
+ headers["anthropic-version"] = "2023-06-01";
86
+ if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
87
+ if (!headers["Accept"]) headers["Accept"] = parsed.stream ? "text/event-stream" : "application/json";
88
+
89
+ return {
90
+ ...req,
91
+ url,
92
+ headers,
93
+ redirect: "manual",
94
+ };
95
+ },
96
+ };
97
+ }
@@ -1,6 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import type { OcxContentPart, OcxParsedRequest } from "../types";
3
- import { antigravityUserAgent } from "./client-fingerprint";
3
+ import { antigravityCliUserAgent, antigravityUserAgent } from "./client-fingerprint";
4
4
 
5
5
  /**
6
6
  * Antigravity request User-Agent. Mirrors the real Antigravity IDE UA
@@ -11,6 +11,27 @@ import { antigravityUserAgent } from "./client-fingerprint";
11
11
  */
12
12
  export const ANTIGRAVITY_REQUEST_UA = antigravityUserAgent();
13
13
 
14
+ /**
15
+ * Antigravity CLI User-Agent. CCA serves Gemini 4 Argon only to the CLI client family, and it
16
+ * 404s other agent models (`gemini-3.7-flash-tiered`, `gemini-3.1-pro-low`) under it, so the
17
+ * choice is per wire model: see `antigravityUserAgentForWireModel`.
18
+ */
19
+ export const ANTIGRAVITY_CLI_REQUEST_UA = antigravityCliUserAgent();
20
+
21
+ /**
22
+ * Model discovery (`:fetchAvailableModels`) uses the CLI UA so Argon's wire ids are listed;
23
+ * under the IDE UA they are absent.
24
+ */
25
+ export const ANTIGRAVITY_DISCOVERY_UA = ANTIGRAVITY_CLI_REQUEST_UA;
26
+
27
+ /** Wire ids CCA serves only to the CLI client family (verified 2026-10-14). */
28
+ const ANTIGRAVITY_CLI_ONLY_WIRE_MODEL = /^gemini-4-argon(?:-(?:low|medium|high))?$/;
29
+
30
+ /** The User-Agent an Antigravity inference request for `wireModelId` must carry. */
31
+ export function antigravityUserAgentForWireModel(wireModelId: string): string {
32
+ return ANTIGRAVITY_CLI_ONLY_WIRE_MODEL.test(wireModelId) ? ANTIGRAVITY_CLI_REQUEST_UA : ANTIGRAVITY_REQUEST_UA;
33
+ }
34
+
14
35
  /**
15
36
  * Whether a stored `OcxToolCall.thoughtSignature` is a REAL upstream Gemini signature versus a
16
37
  * foreign id that must not be forwarded to Gemini/Antigravity.
@@ -1,6 +1,8 @@
1
+ import { openCodeZenGeminiEndpoint } from "../types/opencode-zen";
1
2
  import type { AdapterFetchContext, AdapterRequest, ProviderAdapter } from "./base";
2
3
  import { debugDroppedFrame, debugProviderDiagnosticLazy } from "../lib/debug";
3
4
  import { createToolCallIdAllocator } from "./tool-call-id";
5
+ import { openCodeGoGeminiEndpoint } from "../types/opencode-go";
4
6
  import { createImageBudget, materializeInlineImage, MAX_ENCODED_BYTES_PER_IMAGE, artifactHttpUrl } from "../images/artifacts";
5
7
  import type {
6
8
  AdapterEvent,
@@ -17,11 +19,11 @@ import type {
17
19
  import { isAllowedToolChoice, namespacedToolName, resolveToolChoiceWireName, toolChoiceToolPredicate } from "../types";
18
20
  import type { OcxTool } from "../types";
19
21
  import { contentPartsToText, parseDataUrl } from "./image";
20
- import { getVertexAccessToken } from "../lib/gcp-adc";
22
+ import { GCP_CREDENTIAL_MARKER_PREFIX, gcpCredentialMarkerAccount, getVertexAccessToken } from "../lib/gcp-adc";
21
23
  import { fetchAntigravityWithRetry, fetchVertexWithRetry } from "./google-http";
22
24
  import { safeAntigravityHttpErrorMessage, safeVertexHttpErrorMessage } from "./google-errors";
23
25
  import { isVertexTruncatedTurn, vertexTruncationErrorEvent } from "./google-truncation";
24
- import { ANTIGRAVITY_REQUEST_UA, antigravitySessionAnchor, antigravitySessionId, isLikelyRealThoughtSignature, sanitizeAntigravityClaudeSignatures } from "./google-antigravity-wire";
26
+ import { antigravitySessionAnchor, antigravityUserAgentForWireModel, antigravitySessionId, isLikelyRealThoughtSignature, sanitizeAntigravityClaudeSignatures } from "./google-antigravity-wire";
25
27
  import { summarizeGoogleWireShape } from "./google-wire-shape";
26
28
  import { compileGoogleWireBody } from "./google-wire-compiler";
27
29
  import type { GoogleToolSchemaLossReport, GoogleToolSchemaProfile } from "./google-tool-schema";
@@ -174,7 +176,15 @@ function resolveDirectGeminiWireModelId(modelId: string, applyRenames: boolean):
174
176
 
175
177
  /** Vertex API key: provider.apiKey if it looks real (not a sentinel), else GOOGLE_CLOUD_API_KEY env. */
176
178
  function resolveVertexApiKey(optKey?: string): string | undefined {
177
- const realKey = optKey && !optKey.startsWith("<") && optKey !== "N/A" ? optKey : undefined;
179
+ // A `gcp-sa:` marker is the keychain-backed credential reference (see gcp-adc): it is not
180
+ // API-key material, so it must not be sent as x-goog-api-key — the ADC branch below handles it.
181
+ // AND the marker means the operator named one credential explicitly: the GOOGLE_CLOUD_API_KEY
182
+ // env fallback must NOT fire (it would silently route this provider's inference through the
183
+ // ambient env key instead of the configured service account).
184
+ if (optKey && optKey.startsWith(GCP_CREDENTIAL_MARKER_PREFIX)) return undefined;
185
+ const realKey = optKey && !optKey.startsWith("<") && optKey !== "N/A"
186
+ ? optKey
187
+ : undefined;
178
188
  return realKey || process.env.GOOGLE_CLOUD_API_KEY;
179
189
  }
180
190
 
@@ -864,6 +874,7 @@ function invalidGoogleShapeEvent(
864
874
  };
865
875
  }
866
876
 
877
+ /** Build Gemini transport and response parsing for AI Studio, Vertex, Cloud Code Assist or Go. */
867
878
  export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapter {
868
879
  const toolSchemaPolicy = provider.googleToolSchemaPolicy ?? "compatible";
869
880
  const toolSchemaProfile = {
@@ -945,6 +956,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
945
956
  }
946
957
  : {}),
947
958
 
959
+ /** Compile an admitted request into the selected Gemini endpoint, body and authentication. */
948
960
  async buildRequest(parsed: OcxParsedRequest) {
949
961
  // Structured-output admission runs FIRST, before messagesToGeminiFormat writes
950
962
  // lastInjectedCallIds/lastReasoningReplayScope: a refused request must not leave
@@ -983,7 +995,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
983
995
  mapReasoningEffort(provider, parsed.modelId, parsed.options.reasoning),
984
996
  provider.baseUrl,
985
997
  ).wireModelId
986
- : provider.googleMode === "vertex"
998
+ : provider.googleMode === "vertex" || openCodeZenGeminiEndpoint(provider, parsed.modelId) !== undefined
987
999
  ? parsed.modelId
988
1000
  : resolveDirectGeminiWireModelId(parsed.modelId, provider.directGeminiWireRenames !== false);
989
1001
  returnsThoughtSummaries = provider.googleMode === "cloud-code-assist"
@@ -1155,7 +1167,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
1155
1167
  requestId: `agent-${crypto.randomUUID()}`,
1156
1168
  request,
1157
1169
  };
1158
- headers["User-Agent"] = ANTIGRAVITY_REQUEST_UA;
1170
+ headers["User-Agent"] = antigravityUserAgentForWireModel(wireModelId);
1159
1171
  headers["Authorization"] = `Bearer ${token}`;
1160
1172
  return { url, method: "POST", headers, body: JSON.stringify(envelope) };
1161
1173
  }
@@ -1197,16 +1209,31 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
1197
1209
  if (locationError) throw new Error(locationError);
1198
1210
  const host = location === "global" ? "aiplatform.googleapis.com" : `${location}-aiplatform.googleapis.com`;
1199
1211
  const url = `https://${host}/v1/projects/${project}/locations/${location}/publishers/google/models/${parsed.modelId}:${method}${streamParam}`;
1200
- const token = await getVertexAccessToken();
1212
+ // The marker account travels per-request as an argument (never process-global state): a
1213
+ // module-level "active marker" written at routing time would race across concurrent
1214
+ // requests for different providers and could resolve one call with another's credential.
1215
+ const markerAccount = gcpCredentialMarkerAccount(provider.apiKey);
1216
+ const token = await getVertexAccessToken({ markerAccount });
1201
1217
  headers["Authorization"] = `Bearer ${token}`;
1202
1218
  return { url, method: "POST", headers, body: JSON.stringify(compiled.body) };
1203
1219
  }
1204
1220
 
1205
- // ai-studio (default): Generative Language API + x-goog-api-key.
1206
- const url = `${provider.baseUrl}/v1beta/models/${routedModelId}:${method}${streamParam}`;
1221
+ // Go and Zen use separate guarded Gemini endpoints; AI Studio retains /v1beta.
1222
+ const goEndpoint = openCodeGoGeminiEndpoint(provider, routedModelId);
1223
+ const zenEndpoint = openCodeZenGeminiEndpoint(provider, routedModelId);
1224
+ const endpoint = goEndpoint ?? zenEndpoint ?? `${provider.baseUrl}/v1beta/models/${routedModelId}`;
1225
+ const url = `${endpoint}:${method}${streamParam}`;
1207
1226
  const apiKey = provider.apiKey?.trim();
1208
- if (!apiKey) throw new Error("google (AI Studio) requires a non-empty API key");
1209
- headers["x-goog-api-key"] = apiKey;
1227
+ if (!apiKey) throw new Error(`${goEndpoint ? "OpenCode Go" : zenEndpoint ? "OpenCode Zen" : "google (AI Studio)"} requires a non-empty API key`);
1228
+ if (goEndpoint) {
1229
+ // Console inference documents Bearer auth. Send only the selected Go key.
1230
+ for (const name of Object.keys(headers)) {
1231
+ if (["authorization", "x-goog-api-key", "x-api-key"].includes(name.toLowerCase())) delete headers[name];
1232
+ }
1233
+ headers["Authorization"] = `Bearer ${apiKey}`;
1234
+ } else {
1235
+ headers["x-goog-api-key"] = apiKey;
1236
+ }
1210
1237
 
1211
1238
  const compiled = compileGoogleWireBody(body, toolSchemaProfile, toolSchemaPolicy);
1212
1239
  reportToolSchemaLoss(compiled.toolSchemaLossReport);
@@ -7,6 +7,7 @@ import { EMPTY_TOOL_OUTPUT_ANNOTATION, isWhitespaceOnlyTextPartArray } from "../
7
7
  import { identifyRoutedModel } from "../identity";
8
8
  import { buildNonOpenAIToolCatalogNudgeForTools, shouldInjectNonOpenAIToolCatalogNudge } from "../tool-catalog-nudge";
9
9
  import { peekReasoningForCall } from "../../responses/reasoning-replay-cache";
10
+ import { chatReasoningReplayPolicy } from "./reasoning-replay";
10
11
  import type { ClaudeThinkingProjection } from "../../lib/claude-request-projection";
11
12
  import { inlineDocumentDataUrl } from "../../responses/inline-document";
12
13
  import type { OcxAssistantMessage, OcxContentPart, OcxParsedRequest, OcxProviderConfig, OcxTextContent, OcxThinkingContent, OcxToolCall } from "../../types";
@@ -75,7 +76,7 @@ export function openAIChatSerializesThinking(
75
76
  modelId: string,
76
77
  ): ClaudeThinkingProjection {
77
78
  return {
78
- text: modelInList(provider.preserveReasoningContentModels, modelId),
79
+ text: chatReasoningReplayPolicy(provider, modelId).preserve,
79
80
  // The wire has no `signature` field — base64 replay tokens are Anthropic-wire-only.
80
81
  signature: false,
81
82
  // A `redacted_thinking` block is opaque provider data with no Chat representation: the
@@ -267,7 +268,7 @@ export function messagesToChatFormat(parsed: OcxParsedRequest, provider: OcxProv
267
268
  // recorded under every call id — join unique texts only.
268
269
  if (cached.length > 0) {
269
270
  reasoningContent = [...new Set(cached)].join("\n");
270
- } else if (modelInList(provider.requiresReasoningPlaceholderModels ?? provider.preserveReasoningContentModels, parsed.modelId)) {
271
+ } else if (chatReasoningReplayPolicy(provider, parsed.modelId).placeholder) {
271
272
  // Fallback (extends #950 and #1193; fixes #5421): the replay cache is
272
273
  // bounded (64 entries / 256 KiB / 1 h TTL) and always misses on
273
274
  // long sessions, and some thinking/tool rounds carry no recorded
@@ -354,7 +355,7 @@ export function messagesToChatFormat(parsed: OcxParsedRequest, provider: OcxProv
354
355
  const orphanReasoning =
355
356
  cachedReasoning
356
357
  || (wireSerializesThinking
357
- && modelInList(provider.requiresReasoningPlaceholderModels ?? provider.preserveReasoningContentModels, parsed.modelId)
358
+ && chatReasoningReplayPolicy(provider, parsed.modelId).placeholder
358
359
  ? " "
359
360
  : undefined);
360
361
  const orphanReasoningFields: Record<string, unknown> = !orphanReasoning
@@ -14,6 +14,8 @@ import { modelRecordValue } from "../../reasoning-effort";
14
14
  import { modelInList, type OcxProviderConfig } from "../../types";
15
15
  import { chatParallelToolCallsWireValue } from "./parallel-tool-calls";
16
16
  import { applyExplicitChatReasoningWirePolicy } from "./reasoning-wire";
17
+ import { replayNativeChatReasoning } from "./reasoning-replay";
18
+ import type { OcxReasoningReplayScopeRef } from "../../types";
17
19
 
18
20
  const CHAT_PASSTHROUGH_FIELDS = [
19
21
  "audio",
@@ -55,17 +57,19 @@ export function buildOpenAIChatPassthroughRequest(
55
57
  fastPolicy: ResolvedFastPolicy = fastPolicyForModel(provider, modelId, undefined, "chat"),
56
58
  fastMode?: boolean,
57
59
  providerName?: string,
60
+ replayScope?: OcxReasoningReplayScopeRef,
58
61
  ): AdapterRequest {
59
62
  const { url, headers, hasCredential } = openAIChatTransport(provider);
60
63
 
61
64
  const body: Record<string, unknown> = {
62
65
  model: provider.modelSuffixBracketStrip ? stripBracketedModelSuffix(modelId) : modelId,
63
- // The caller's messages are forwarded as they arrived, with one exception: an operator who
66
+ // The caller's messages retain their wire shape. An operator who
64
67
  // recorded that this destination rejects the `developer` role gets that role converted in
65
68
  // place. Verbatim was not neutral there — it sent the role anyway and the turn failed
66
69
  // upstream with a 400 before the model saw it. An unrecorded destination is still verbatim,
67
70
  // and the conversion changes the role of those messages and nothing else, so the position
68
- // of every message and every other field survive unchanged.
71
+ // of every message and every other field survive unchanged. Missing thinking history is
72
+ // repaired below using the same preserve policy as the translated Chat builder.
69
73
  messages: applyExplicitChatDeveloperRole(
70
74
  frameAgentRouterMessages(provider.baseUrl, rawBody.messages),
71
75
  provider,
@@ -75,6 +79,8 @@ export function buildOpenAIChatPassthroughRequest(
75
79
  for (const field of CHAT_PASSTHROUGH_FIELDS) {
76
80
  if (rawBody[field] !== undefined) body[field] = rawBody[field];
77
81
  }
82
+ body.messages = replayNativeChatReasoning(body.messages, provider, modelId, replayScope,
83
+ Array.isArray(rawBody.tools) && rawBody.tools.length > 0);
78
84
  if (protectGlmSummaryBudget(body, provider.baseUrl, body.reasoning_effort)) body.reasoning_effort = "low";
79
85
  const rawEfforts = modelRecordValue(provider.modelReasoningEfforts, modelId) ?? provider.reasoningEfforts;
80
86
  const reasoningDisabled = modelInList(provider.noReasoningModels, modelId) || rawEfforts?.length === 0;
@@ -0,0 +1,52 @@
1
+ import { modelInList, type OcxProviderConfig, type OcxReasoningReplayScopeRef } from "../../types";
2
+ import { peekReasoningForCall } from "../../responses/reasoning-replay-cache";
3
+
4
+ type Rec = Record<string, unknown>;
5
+ export const isChatRecord = (value: unknown): value is Rec =>
6
+ value !== null && typeof value === "object" && !Array.isArray(value);
7
+
8
+ const isDeepSeekThinkingModel = (modelId: string): boolean =>
9
+ /(?:^|\/)deepseek-(?:v\d+(?:\.\d+)*-(?:flash|pro)|flash|pro)(?:$|[-_:])/i.test(modelId);
10
+
11
+ /** DeepSeek thinking tool replay is a model contract, independent of the gateway's name. */
12
+ export function chatReasoningReplayPolicy(provider: OcxProviderConfig, modelId: string): {
13
+ preserve: boolean; placeholder: boolean;
14
+ } {
15
+ // Match whole model-family tokens, including dotted versions, namespace and deployment suffixes.
16
+ // Legacy chat/reasoner and distilled R1 models do not share the thinking tool-call contract.
17
+ const preserve = provider.preserveReasoningContentModels === undefined
18
+ ? isDeepSeekThinkingModel(modelId)
19
+ : modelInList(provider.preserveReasoningContentModels, modelId);
20
+ return {
21
+ preserve,
22
+ placeholder: preserve && (provider.requiresReasoningPlaceholderModels === undefined
23
+ ? true
24
+ : modelInList(provider.requiresReasoningPlaceholderModels, modelId)),
25
+ };
26
+ }
27
+
28
+ /** Repair missing native history without mutating caller bodies used by retries/combo siblings. */
29
+ export function replayNativeChatReasoning(
30
+ messages: unknown,
31
+ provider: OcxProviderConfig,
32
+ modelId: string,
33
+ scope?: OcxReasoningReplayScopeRef,
34
+ hasTools = false,
35
+ ): unknown {
36
+ const policy = chatReasoningReplayPolicy(provider, modelId);
37
+ if (!policy.preserve || !Array.isArray(messages)
38
+ || modelInList(provider.reasoningDetailsModels, modelId)) return messages;
39
+ return messages.map(message => {
40
+ if (!isChatRecord(message) || message.role !== "assistant"
41
+ || (typeof message.reasoning_content === "string" && message.reasoning_content.length > 0)) return message;
42
+ const calls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
43
+ // DeepSeek's tools contract covers all prior assistant turns, even plain answers.
44
+ // Those turns have no call id for original replay; only the configured fallback applies.
45
+ if (calls.length === 0 && !(hasTools && isDeepSeekThinkingModel(modelId))) return message;
46
+ const cached = calls.filter(isChatRecord)
47
+ .map(tool => typeof tool.id === "string" ? peekReasoningForCall(tool.id, scope) : undefined)
48
+ .filter((text): text is string => typeof text === "string" && text.length > 0);
49
+ const reasoning = cached.length > 0 ? [...new Set(cached)].join("\n") : policy.placeholder ? " " : undefined;
50
+ return reasoning === undefined ? message : { ...message, reasoning_content: reasoning };
51
+ });
52
+ }
@@ -1,6 +1,7 @@
1
1
  import { diagnoseInvalidToolCalls, isRecord, type InvalidToolCallDiagnostic } from "./tool-call-validation";
2
2
  import { TranslatorBudgetExceededError, type TranslatorBudget } from "../../lib/translator-budget";
3
- import type { AdapterEvent, OcxUsage } from "../../types";
3
+ import type { AdapterEvent, OcxProviderConfig, OcxUsage } from "../../types";
4
+ import { createInlineThinkContentSplitter } from "../inline-think-tags";
4
5
 
5
6
  export function stopReasonFor(finishReason: unknown): "max_tokens" | "content_filter" | undefined {
6
7
  return finishReason === "length"
@@ -18,6 +19,63 @@ export function reasoningTextFrom(record: Record<string, unknown>): string | und
18
19
  : undefined;
19
20
  }
20
21
 
22
+ type ChatContentEvent = Extract<AdapterEvent, { type: "text_delta" | "reasoning_raw_delta" | "error" }>;
23
+
24
+ /** Mistral can mix typed blocks and strings in one response. Other destinations keep their parser. */
25
+ export function chatContentEvents(content: unknown, baseUrl: string, usage?: OcxUsage, buffered = false): ChatContentEvent[] {
26
+ if (typeof content === "string") return content.length > 0 || buffered ? [{ type: "text_delta", text: content }] : [];
27
+ if (!Array.isArray(content)) return [];
28
+ let host: string;
29
+ try { host = new URL(baseUrl).hostname; } catch { return []; }
30
+ if (host !== "api.mistral.ai") return [];
31
+ const invalid = (): ChatContentEvent[] => [{
32
+ type: "error", status: 502, errorType: "upstream_error",
33
+ message: "unsupported Mistral content block", ...(usage ? { usage } : {}),
34
+ }];
35
+ const events: ChatContentEvent[] = [];
36
+ for (const block of content) {
37
+ if (!isRecord(block)) return invalid();
38
+ if (block.type === "text" && typeof block.text === "string") {
39
+ if (block.text.length > 0 || buffered) events.push({ type: "text_delta", text: block.text });
40
+ } else if (block.type === "thinking" && Array.isArray(block.thinking)) {
41
+ for (const inner of block.thinking) {
42
+ if (!isRecord(inner) || inner.type !== "text" || typeof inner.text !== "string") return invalid();
43
+ if (inner.text.length > 0) events.push({ type: "reasoning_raw_delta", text: inner.text });
44
+ }
45
+ } else return invalid();
46
+ }
47
+ return events;
48
+ }
49
+
50
+ /** Keep adjacent text together; typed reasoning flushes and resets inline-tag parsing. */
51
+ export function createChatContentSplitter(provider: OcxProviderConfig, modelId: string | undefined, budget: TranslatorBudget) {
52
+ let splitter = createInlineThinkContentSplitter(provider.inlineThinkTagModels, modelId, budget);
53
+ return {
54
+ feed(event: ChatContentEvent): AdapterEvent[] {
55
+ if (event.type === "error") return [event];
56
+ if (event.type === "text_delta") return splitter.feed(event.text);
57
+ const pending = splitter.flush();
58
+ splitter.dispose();
59
+ splitter = createInlineThinkContentSplitter(provider.inlineThinkTagModels, modelId, budget);
60
+ return [...pending, event];
61
+ },
62
+ flush: () => splitter.flush(),
63
+ dispose: () => splitter.dispose(),
64
+ };
65
+ }
66
+
67
+ /** Split a buffered answer with the same typed-reasoning boundaries as a stream. */
68
+ export function splitChatContentEvents(content: unknown, provider: OcxProviderConfig, modelId: string | undefined, budget: TranslatorBudget, usage?: OcxUsage): AdapterEvent[] {
69
+ const events = chatContentEvents(content, provider.baseUrl, usage, true);
70
+ if (events.some(event => event.type === "error")) return events;
71
+ const splitter = createChatContentSplitter(provider, modelId, budget);
72
+ try {
73
+ return [...events.flatMap(event => splitter.feed(event)), ...splitter.flush()];
74
+ } finally {
75
+ splitter.dispose();
76
+ }
77
+ }
78
+
21
79
  export interface ReasoningDetailSegment {
22
80
  key: string;
23
81
  text: string;
@@ -5,7 +5,6 @@ import { applyExplicitChatReasoningWirePolicy } from "./openai-chat/reasoning-wi
5
5
  import type { AdapterRequest, IncomingMeta, ProviderAdapter } from "./base";
6
6
  import type { AdapterEvent, OcxParsedRequest, OcxProviderConfig, OcxUsage } from "../types";
7
7
  import { modelInList } from "../types";
8
- import { createInlineThinkContentSplitter, splitInlineThinkContent } from "./inline-think-tags";
9
8
  import { mapReasoningEffort } from "../reasoning-effort";
10
9
  import { debugProviderDiagnostic } from "../lib/debug";
11
10
  import { sseFieldValue } from "../lib/sse-decoder";
@@ -28,6 +27,7 @@ import {
28
27
  type InvalidToolCallDiagnostic,
29
28
  } from "./openai-chat/tool-call-validation";
30
29
  import {
30
+ chatContentEvents, createChatContentSplitter, splitChatContentEvents,
31
31
  createReasoningDetailSnapshotTracker,
32
32
  invalidChoicesEvent,
33
33
  invalidToolCallsEvent,
@@ -368,7 +368,7 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
368
368
  const reasoningDetailsOptIn = modelInList(provider.reasoningDetailsModels, lastRequestedModelId ?? "");
369
369
  // A gateway with no server-side reasoning parser leaves thinking inline in `content` as
370
370
  // <think> blocks, which would otherwise render as the answer. Passthrough unless opted in.
371
- const inlineThink = createInlineThinkContentSplitter(provider.inlineThinkTagModels, lastRequestedModelId, budget);
371
+ const inlineThink = createChatContentSplitter(provider, lastRequestedModelId, budget);
372
372
  const emitContent = function* (events: AdapterEvent[]): Generator<AdapterEvent> {
373
373
  for (const event of events) {
374
374
  // Any other event keeps its place behind held text instead of overtaking it.
@@ -444,8 +444,9 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
444
444
  const reasoningText = reasoningTextFrom(delta);
445
445
  if (reasoningText !== undefined) yield* toolCallContent.hold({ type: "reasoning_raw_delta", text: reasoningText });
446
446
  }
447
- if (typeof delta.content === "string" && delta.content.length > 0) {
448
- yield* emitContent(inlineThink.feed(delta.content));
447
+ for (const event of chatContentEvents(delta.content, provider.baseUrl, pendingUsage)) {
448
+ if (event.type === "error") return yield* terminateWithError(event);
449
+ yield* emitContent(inlineThink.feed(event));
449
450
  }
450
451
 
451
452
  const rawToolCalls = delta.tool_calls;
@@ -767,7 +768,9 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
767
768
  }
768
769
  if (reasoningText !== undefined) events.push({ type: "reasoning_raw_delta", text: reasoningText });
769
770
  const contentStart = events.length;
770
- if (typeof msg.content === "string") events.push(...splitInlineThinkContent(provider.inlineThinkTagModels, lastRequestedModelId, budget, msg.content));
771
+ const contentEvents = splitChatContentEvents(msg.content, provider, lastRequestedModelId, budget, usage);
772
+ if (contentEvents.some(event => event.type === "error")) return contentEvents;
773
+ events.push(...contentEvents);
771
774
  const contentEnd = events.length;
772
775
  const answerText = events.slice(contentStart).map(event => (event.type === "text_delta" ? event.text : "")).join("");
773
776
  // Each call holds the delta event it emitted, so the batch repair sets its arguments later.