@bitkyc08/opencodex 2.59.0 → 2.61.0-preview.20260922

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 (374) hide show
  1. package/AGENTS_INSTALL.md +64 -0
  2. package/README.md +28 -1
  3. package/bin/ocx.mjs +382 -209
  4. package/gui/dist/assets/App-E64Rzjap.js +50 -0
  5. package/gui/dist/assets/Tray-_nfzD8k4.js +1 -0
  6. package/gui/dist/assets/index-DpdfZWMK.js +86 -0
  7. package/gui/dist/assets/index-_bpvxJu0.css +1 -0
  8. package/gui/dist/assets/usage-companion-chart-DtoK7T6h.js +1 -0
  9. package/gui/dist/favicon.png +0 -0
  10. package/gui/dist/index.html +2 -2
  11. package/gui/dist/provider-icons/stepfun-color.svg +1 -0
  12. package/package.json +8 -1
  13. package/src/adapters/anthropic-image-codec.ts +16 -2
  14. package/src/adapters/anthropic-image-normalize.ts +49 -2
  15. package/src/adapters/anthropic.ts +20 -1
  16. package/src/adapters/base.ts +23 -0
  17. package/src/adapters/coding-agent/protocol.ts +36 -6
  18. package/src/adapters/coding-agent/turn.ts +32 -4
  19. package/src/adapters/command-code.ts +52 -4
  20. package/src/adapters/cursor/catalog.ts +51 -7
  21. package/src/adapters/cursor/checkpoint-store.ts +3 -0
  22. package/src/adapters/cursor/discovery.ts +11 -8
  23. package/src/adapters/cursor/live-transport.ts +26 -9
  24. package/src/adapters/cursor/protobuf-request.ts +6 -3
  25. package/src/adapters/cursor/request-builder.ts +20 -4
  26. package/src/adapters/cursor/transport.ts +19 -0
  27. package/src/adapters/cursor.ts +14 -3
  28. package/src/adapters/declaration-carrier.ts +45 -0
  29. package/src/adapters/devin/cloud-direct/chat.ts +3 -1
  30. package/src/adapters/devin/cloud-direct/stated-reset-retry.ts +42 -5
  31. package/src/adapters/devin.ts +125 -36
  32. package/src/adapters/google-antigravity-replay.ts +1 -1
  33. package/src/adapters/google-antigravity-wire.ts +34 -7
  34. package/src/adapters/google-errors.ts +7 -1
  35. package/src/adapters/google-http.ts +49 -10
  36. package/src/adapters/google-tool-schema.ts +595 -31
  37. package/src/adapters/google-wire-compiler.ts +93 -10
  38. package/src/adapters/google-wire-shape.ts +461 -0
  39. package/src/adapters/google.ts +66 -11
  40. package/src/adapters/image.ts +4 -1
  41. package/src/adapters/input-media-guard.ts +21 -9
  42. package/src/adapters/kiro/usage.ts +3 -2
  43. package/src/adapters/kiro-tool-fallback.ts +1 -1
  44. package/src/adapters/ollama-native.ts +6 -0
  45. package/src/adapters/openai-chat/developer-role.ts +61 -0
  46. package/src/adapters/openai-chat/messages.ts +46 -27
  47. package/src/adapters/openai-chat/parallel-tool-calls.ts +32 -0
  48. package/src/adapters/openai-chat/passthrough.ts +33 -9
  49. package/src/adapters/openai-chat/reasoning-wire.ts +89 -0
  50. package/src/adapters/openai-chat-images.ts +3 -1
  51. package/src/adapters/openai-chat.ts +23 -58
  52. package/src/adapters/openai-responses/image-gen.ts +8 -6
  53. package/src/adapters/openai-responses/passthrough.ts +17 -3
  54. package/src/adapters/openai-responses/reasoning.ts +7 -0
  55. package/src/adapters/opencode-go-additional-tools.ts +12 -2
  56. package/src/adapters/registry.ts +3 -2
  57. package/src/adapters/run-turn-queue.ts +178 -29
  58. package/src/adapters/xai-web-search.ts +16 -1
  59. package/src/bridge/errors.ts +8 -2
  60. package/src/bridge/response-json.ts +9 -1
  61. package/src/bridge/sse.ts +13 -151
  62. package/src/chat/inbound.ts +141 -5
  63. package/src/claude/desktop-3p.ts +7 -1
  64. package/src/claude/desktop-first-party.ts +183 -0
  65. package/src/claude/desktop-gateway-state.ts +41 -0
  66. package/src/claude/inbound-content-options.ts +6 -0
  67. package/src/claude/inbound.ts +32 -6
  68. package/src/claude/intercept/connect-proxy.ts +179 -0
  69. package/src/claude/intercept/listener.ts +122 -0
  70. package/src/claude/intercept/local-ca.ts +298 -0
  71. package/src/claude/intercept/runtime.ts +98 -0
  72. package/src/claude/intercept/settings.ts +189 -0
  73. package/src/cli/access.ts +87 -0
  74. package/src/cli/account-auth.ts +19 -0
  75. package/src/cli/account-extended.ts +4 -4
  76. package/src/cli/capabilities.ts +31 -0
  77. package/src/cli/claude-desktop.ts +206 -16
  78. package/src/cli/codex-shim-autorestore.ts +3 -0
  79. package/src/cli/companion.ts +56 -0
  80. package/src/cli/dispatch.ts +46 -7
  81. package/src/cli/doctor.ts +28 -9
  82. package/src/cli/ensure-desired-integrations.ts +43 -5
  83. package/src/cli/help.ts +7 -9
  84. package/src/cli/hub.ts +3 -2
  85. package/src/cli/index.ts +203 -59
  86. package/src/cli/init.ts +8 -0
  87. package/src/cli/integrations.ts +7 -1
  88. package/src/cli/opencode.ts +2 -2
  89. package/src/cli/provider.ts +13 -1
  90. package/src/cli/registry.ts +41 -2
  91. package/src/cli/resolve.ts +230 -0
  92. package/src/cli/root.ts +24 -1
  93. package/src/cli/start-ownership-publication.ts +56 -0
  94. package/src/cli/status-probes.ts +2 -18
  95. package/src/cli/status.ts +62 -0
  96. package/src/cli/stop-report.ts +143 -0
  97. package/src/cli/uninstall-plan.ts +9 -0
  98. package/src/client/machine-api.ts +2 -2
  99. package/src/client/machine-listener.ts +4 -7
  100. package/src/client/runtime.ts +26 -2
  101. package/src/clients/aside-profiles.ts +4 -0
  102. package/src/clients/config-export/zcode-store.ts +157 -0
  103. package/src/clients/config-export.ts +36 -0
  104. package/src/codex/account-store.ts +65 -0
  105. package/src/codex/app-server-processes.ts +72 -40
  106. package/src/codex/auth-api/account-list.ts +19 -11
  107. package/src/codex/auth-api/login-flow.ts +6 -1
  108. package/src/codex/auth-api/pool-quota-probe.ts +30 -7
  109. package/src/codex/autostart-health.ts +28 -0
  110. package/src/codex/catalog/build-entries.ts +2 -2
  111. package/src/codex/catalog/effort.ts +3 -3
  112. package/src/codex/catalog/gather-capture.ts +21 -2
  113. package/src/codex/catalog/model-hints.ts +29 -28
  114. package/src/codex/catalog/parsing.ts +7 -0
  115. package/src/codex/catalog/provider-models.ts +43 -17
  116. package/src/codex/catalog/retained-sync.ts +24 -28
  117. package/src/codex/catalog/routed-gather.ts +19 -0
  118. package/src/codex/context-compat.ts +5 -2
  119. package/src/codex/convergence.ts +2 -2
  120. package/src/codex/desired-state.ts +4 -1
  121. package/src/codex/history-job.ts +6 -6
  122. package/src/codex/history-provider.ts +31 -166
  123. package/src/codex/history-rollout-read.ts +174 -0
  124. package/src/codex/inject/config-toml.ts +41 -6
  125. package/src/codex/inject/paginated-openai-compat.ts +90 -0
  126. package/src/codex/inject.ts +18 -15
  127. package/src/codex/injected-marker.ts +18 -0
  128. package/src/codex/internal/catalog-writer.ts +33 -1
  129. package/src/codex/main-account.ts +6 -0
  130. package/src/codex/model-cache.ts +99 -6
  131. package/src/codex/model-entitlement-admission.ts +59 -0
  132. package/src/codex/model-entitlements.ts +116 -54
  133. package/src/codex/native-main-admission.ts +83 -0
  134. package/src/codex/observed-model-denials.ts +101 -8
  135. package/src/codex/prompt-text-probe.ts +9 -6
  136. package/src/codex/routing/health-store.ts +39 -0
  137. package/src/codex/routing/selection.ts +37 -1
  138. package/src/codex/routing.ts +12 -42
  139. package/src/codex/shim-templates.ts +29 -3
  140. package/src/codex/shim.ts +1 -1
  141. package/src/codex/subagent-model-fallback.ts +22 -4
  142. package/src/combos/failover.ts +3 -0
  143. package/src/companion/settings.ts +132 -0
  144. package/src/config/admitted-identity.ts +222 -0
  145. package/src/config/atomic-write.ts +117 -5
  146. package/src/config/diagnostics.ts +22 -1
  147. package/src/config/feature-flags.ts +5 -0
  148. package/src/config/load-degrade.ts +52 -7
  149. package/src/config/process-state.ts +1 -1
  150. package/src/config/proxy-env.ts +8 -2
  151. package/src/config/schema/compaction-triggers.ts +11 -0
  152. package/src/config/schema/config-schema.ts +31 -1
  153. package/src/config/schema/leaf-validators.ts +59 -0
  154. package/src/config.ts +3 -3
  155. package/src/generated/compatibility-version.json +604 -280
  156. package/src/grok/reset-coupons.ts +38 -19
  157. package/src/images/loop.ts +6 -1
  158. package/src/integrations/aside-profile-context.ts +37 -3
  159. package/src/integrations/aside-profile-journal.ts +68 -3
  160. package/src/integrations/aside-profiles.ts +128 -3
  161. package/src/integrations/config-io.ts +44 -10
  162. package/src/integrations/merge.ts +120 -13
  163. package/src/integrations/mutation-plan.ts +921 -0
  164. package/src/integrations/registry.ts +38 -0
  165. package/src/integrations/state.ts +78 -45
  166. package/src/integrations/target.ts +208 -0
  167. package/src/integrations/writer.ts +134 -110
  168. package/src/lab/conformance/fixture-provider.ts +5 -0
  169. package/src/lab/live/transport.ts +4 -0
  170. package/src/lab/live/types.ts +5 -0
  171. package/src/lab/subject/behavior-fingerprint.ts +1 -1
  172. package/src/lib/admin-secrets.ts +9 -1
  173. package/src/lib/browser-launch-notice.ts +59 -0
  174. package/src/lib/bun-runtime.ts +6 -2
  175. package/src/lib/debug-log-buffer.ts +6 -1
  176. package/src/lib/debug.ts +63 -0
  177. package/src/lib/errors.ts +79 -0
  178. package/src/lib/http-response-semantics.ts +57 -0
  179. package/src/lib/lab-live-pinned-sender.ts +26 -12
  180. package/src/lib/open-url.ts +51 -7
  181. package/src/lib/package-tree-integrity.ts +2 -1
  182. package/src/lib/package-version.ts +8 -0
  183. package/src/lib/pinned-http.ts +142 -2
  184. package/src/lib/plain-data.ts +103 -0
  185. package/src/lib/process-control.ts +13 -5
  186. package/src/lib/provider-egress.ts +310 -0
  187. package/src/lib/provider-outbound.ts +109 -16
  188. package/src/lib/proxy-env.ts +82 -7
  189. package/src/lib/request-execution-budget.ts +72 -0
  190. package/src/lib/request-failure-attribution.ts +183 -0
  191. package/src/lib/request-failure-model.ts +236 -0
  192. package/src/lib/request-resend-gate.ts +138 -0
  193. package/src/lib/socks5-fetch.ts +136 -26
  194. package/src/lib/spend-ledger-owner.ts +364 -0
  195. package/src/lib/spend-reservation-ledger.ts +218 -27
  196. package/src/lib/standalone.ts +16 -0
  197. package/src/lib/upstream-retry.ts +167 -16
  198. package/src/lib/windows-system-proxy.ts +16 -11
  199. package/src/lib/winsw.ts +2 -2
  200. package/src/oauth/callback-server.ts +4 -3
  201. package/src/oauth/generic-account-failover.ts +1 -0
  202. package/src/oauth/health.ts +12 -1
  203. package/src/oauth/index.ts +27 -108
  204. package/src/oauth/login-cli.ts +80 -29
  205. package/src/oauth/login-flow-state.ts +127 -0
  206. package/src/providers/api-key-resolve.ts +133 -0
  207. package/src/providers/api-key-selection.ts +5 -1
  208. package/src/providers/derive.ts +34 -17
  209. package/src/providers/devin-cli-authmode-migration.ts +14 -10
  210. package/src/providers/key-failover.ts +97 -19
  211. package/src/providers/key-store.ts +34 -110
  212. package/src/providers/model-rename-fields.ts +147 -0
  213. package/src/providers/model-rename-migration.ts +179 -38
  214. package/src/providers/model-rename-startup.ts +7 -5
  215. package/src/providers/openai-virtual-models.ts +42 -2
  216. package/src/providers/quota/antigravity.ts +22 -2
  217. package/src/providers/quota/vendor-probes-key.ts +38 -23
  218. package/src/providers/reasoning-metadata.ts +43 -18
  219. package/src/providers/registry/entries-core.ts +47 -20
  220. package/src/providers/registry/entries-extended.ts +63 -4
  221. package/src/providers/registry/model-ids.ts +168 -0
  222. package/src/providers/registry/model-seeds.ts +56 -10
  223. package/src/providers/registry/types.ts +2 -0
  224. package/src/providers/resolved-model-policy-merge.ts +167 -0
  225. package/src/providers/resolved-model-policy.ts +406 -0
  226. package/src/providers/stale-vision-classification-migration.ts +137 -0
  227. package/src/providers/xai-transport.ts +12 -1
  228. package/src/reasoning-effort.ts +8 -0
  229. package/src/responses/apply-patch-envelope.ts +0 -12
  230. package/src/responses/freeform-wrapper-scan.ts +279 -0
  231. package/src/responses/function-call-compat.ts +38 -1
  232. package/src/responses/inline-document.ts +65 -0
  233. package/src/responses/input-media.ts +42 -8
  234. package/src/responses/legacy-dotted-tool-name-repair.ts +134 -0
  235. package/src/responses/muse-tool-name-alias.ts +19 -0
  236. package/src/responses/parser-content.ts +8 -2
  237. package/src/responses/parser-tools.ts +3 -0
  238. package/src/responses/parser.ts +3 -1
  239. package/src/responses/progressive-freeform-input.ts +130 -0
  240. package/src/responses/reasoning-envelope.ts +30 -0
  241. package/src/responses/schema.ts +3 -0
  242. package/src/responses/state.ts +5 -12
  243. package/src/responses/tool-name-aliases.ts +15 -1
  244. package/src/router.ts +108 -117
  245. package/src/routing/compatibility/behavior.ts +9 -0
  246. package/src/routing/compatibility/subject.ts +16 -1
  247. package/src/server/adapter-resolve.ts +9 -0
  248. package/src/server/admission-model-scope.ts +219 -0
  249. package/src/server/audio-live.ts +9 -3
  250. package/src/server/audio-upstream.ts +18 -0
  251. package/src/server/auth-cors.ts +29 -0
  252. package/src/server/chat-completions.ts +60 -4
  253. package/src/server/chat-native.ts +19 -4
  254. package/src/server/claude-messages.ts +61 -20
  255. package/src/server/effort-row.ts +11 -3
  256. package/src/server/grok-responses-control-frame.ts +160 -1
  257. package/src/server/grok-responses-snapshot-repair.ts +113 -11
  258. package/src/server/gui-freshness.ts +103 -0
  259. package/src/server/gui-static.ts +7 -9
  260. package/src/server/images.ts +59 -6
  261. package/src/server/index/claude-intercept-lifecycle.ts +49 -0
  262. package/src/server/index/serve-options.ts +142 -39
  263. package/src/server/index/spend-ledger-lifecycle.ts +92 -0
  264. package/src/server/index/startup-warnings.ts +24 -0
  265. package/src/server/index/websocket-handler.ts +6 -1
  266. package/src/server/index.ts +34 -38
  267. package/src/server/lifecycle.ts +4 -4
  268. package/src/server/live-call-bindings.ts +6 -0
  269. package/src/server/live.ts +88 -3
  270. package/src/server/management/agent-settings-routes.ts +121 -36
  271. package/src/server/management/aside-profile-routes.ts +266 -7
  272. package/src/server/management/companion-routes.ts +77 -0
  273. package/src/server/management/config-routes.ts +18 -2
  274. package/src/server/management/context.ts +3 -0
  275. package/src/server/management/integration-routes.ts +287 -5
  276. package/src/server/management/logs-usage-routes.ts +19 -0
  277. package/src/server/management/metrics-routes.ts +20 -0
  278. package/src/server/management/model-rows.ts +224 -12
  279. package/src/server/management/native-integration-routes.ts +103 -6
  280. package/src/server/management/oauth-account-routes.ts +45 -7
  281. package/src/server/management/route-registry.ts +20 -0
  282. package/src/server/management/shared.ts +28 -4
  283. package/src/server/management/system-restart.ts +7 -2
  284. package/src/server/management/system-routes.ts +2 -0
  285. package/src/server/management/usage-aggregate-cache.ts +4 -0
  286. package/src/server/management/usage-timeline-routes.ts +44 -0
  287. package/src/server/management-api.ts +10 -9
  288. package/src/server/management-auth.ts +15 -1
  289. package/src/server/proxy-liveness.ts +75 -0
  290. package/src/server/readiness.ts +29 -10
  291. package/src/server/relay-eager.ts +24 -2
  292. package/src/server/relay.ts +138 -12
  293. package/src/server/request-log-failure-attribution.ts +99 -0
  294. package/src/server/request-log.ts +169 -2
  295. package/src/server/request-metrics.ts +298 -0
  296. package/src/server/responses/adapter-continuation.ts +3 -3
  297. package/src/server/responses/adapter-dispatch.ts +11 -6
  298. package/src/server/responses/codex-ws-wire.ts +34 -8
  299. package/src/server/responses/combo-stream-preflight.ts +168 -6
  300. package/src/server/responses/compact.ts +43 -10
  301. package/src/server/responses/compaction-routing.ts +111 -0
  302. package/src/server/responses/core-codex-account.ts +8 -3
  303. package/src/server/responses/core-combo.ts +7 -7
  304. package/src/server/responses/core-normalize.ts +6 -12
  305. package/src/server/responses/core-opaque-recovery.ts +91 -0
  306. package/src/server/responses/core-options.ts +4 -0
  307. package/src/server/responses/encrypted-payload.ts +20 -2
  308. package/src/server/responses/fetch-helpers.ts +124 -8
  309. package/src/server/responses/input-admission.ts +10 -0
  310. package/src/server/responses/passthrough-delivery.ts +45 -15
  311. package/src/server/responses/passthrough-dispatch.ts +215 -44
  312. package/src/server/responses/passthrough-error.ts +27 -8
  313. package/src/server/responses/policy-fallback.ts +5 -13
  314. package/src/server/responses/request-prepare.ts +109 -18
  315. package/src/server/responses/request-send-budget.ts +17 -1
  316. package/src/server/responses/request-sidecar-auth.ts +1 -1
  317. package/src/server/responses/request-transport.ts +26 -6
  318. package/src/server/responses/reset-replay.ts +108 -0
  319. package/src/server/responses/run-turn-execution.ts +25 -3
  320. package/src/server/responses/sidecar-execution.ts +17 -2
  321. package/src/server/responses/ws-upstream.ts +14 -27
  322. package/src/server/responses-custom-tool-repair.ts +27 -54
  323. package/src/server/responses-request-tool-scope.ts +214 -0
  324. package/src/server/responses-undeclared-tool-guard.ts +35 -2
  325. package/src/server/search.ts +25 -1
  326. package/src/server/sse-payload-rewrite.ts +1 -1
  327. package/src/server/usage-ledger-retention.ts +73 -0
  328. package/src/service/cli.ts +48 -2
  329. package/src/service/health.ts +3 -2
  330. package/src/service/install-state-contract.d.mts +27 -0
  331. package/src/service/install-state-contract.mjs +34 -0
  332. package/src/service/launchd.ts +1 -1
  333. package/src/service/orchestration.ts +2 -4
  334. package/src/service/ownership-compatibility.ts +164 -0
  335. package/src/service/ownership-mutation-lease.d.mts +32 -0
  336. package/src/service/ownership-mutation-lease.mjs +211 -0
  337. package/src/service/repair.ts +45 -1
  338. package/src/service/state-lock.ts +269 -0
  339. package/src/service/state-record.d.mts +36 -0
  340. package/src/service/state-record.mjs +138 -0
  341. package/src/service/state.ts +582 -68
  342. package/src/service/windows-taskxml.ts +11 -10
  343. package/src/service.ts +7 -3
  344. package/src/tray/windows-tray.ps1 +156 -4
  345. package/src/types/config.ts +48 -3
  346. package/src/types/provider.ts +91 -0
  347. package/src/types/request.ts +30 -2
  348. package/src/types/tools.ts +33 -0
  349. package/src/types.ts +4 -0
  350. package/src/update/index.ts +207 -63
  351. package/src/update/job.ts +9 -5
  352. package/src/update/ownership-transaction.ts +47 -0
  353. package/src/update/restart-ownership.ts +54 -0
  354. package/src/update/runtime-ownership.d.mts +40 -0
  355. package/src/update/runtime-ownership.mjs +122 -0
  356. package/src/usage/attempt-delivery.ts +198 -0
  357. package/src/usage/cache-diagnostic.ts +305 -0
  358. package/src/usage/failure-fingerprint.ts +118 -0
  359. package/src/usage/failure-projection-cache.ts +174 -0
  360. package/src/usage/failure-projection.ts +174 -0
  361. package/src/usage/ledger-retention.ts +165 -0
  362. package/src/usage/log.ts +126 -79
  363. package/src/usage/request-outcome.ts +150 -0
  364. package/src/usage/retention-contract.ts +28 -0
  365. package/src/usage/summary.ts +2 -2
  366. package/src/usage/telemetry-contract.ts +237 -0
  367. package/src/usage/timeline.ts +236 -0
  368. package/src/vision/eligibility.ts +88 -9
  369. package/src/vision/plan.ts +34 -10
  370. package/src/web-search/alpha-search.ts +21 -1
  371. package/src/web-search/executor.ts +41 -2
  372. package/src/web-search/loop.ts +6 -1
  373. package/gui/dist/assets/index-C5IebErG.js +0 -136
  374. package/gui/dist/assets/index-OESInAjC.css +0 -1
@@ -0,0 +1,89 @@
1
+ import { modelInList, type OcxProviderConfig } from "../../types";
2
+ import type { AdapterRequest } from "../base";
3
+ import { isNativeOpenAIChatTarget } from "./wire";
4
+
5
+ export type ExplicitChatReasoningWireResult =
6
+ | { handled: false }
7
+ | { handled: true; reasoningLog?: AdapterRequest["reasoningLog"] };
8
+
9
+ /**
10
+ * Apply provider-declared reasoning wire policy after the effective provider is resolved.
11
+ * Unset declarations are a no-op so native Chat keeps forwarding the caller's raw field.
12
+ */
13
+ export function applyExplicitChatReasoningWirePolicy(options: {
14
+ provider: OcxProviderConfig;
15
+ modelId: string;
16
+ hasTools: boolean;
17
+ requestedEffort: string | undefined;
18
+ wireEffort: string | undefined;
19
+ reasoningDisabled: boolean;
20
+ body: Record<string, unknown>;
21
+ }): ExplicitChatReasoningWireResult {
22
+ const {
23
+ provider,
24
+ modelId,
25
+ hasTools,
26
+ requestedEffort,
27
+ wireEffort,
28
+ reasoningDisabled,
29
+ body,
30
+ } = options;
31
+
32
+ if (reasoningDisabled) return { handled: false };
33
+ if (hasTools && modelInList(provider.omitReasoningEffortWithToolsModels, modelId)) {
34
+ delete body.reasoning_effort;
35
+ delete body.reasoning;
36
+ return { handled: true };
37
+ }
38
+ if (provider.reasoningWireFormat !== "gateway-object") return { handled: false };
39
+
40
+ const nativeOpenAI = isNativeOpenAIChatTarget(provider);
41
+ if (requestedEffort === "none") {
42
+ if (nativeOpenAI) {
43
+ delete body.reasoning;
44
+ body.reasoning_effort = "none";
45
+ return {
46
+ handled: true,
47
+ reasoningLog: {
48
+ effectiveEffort: "none",
49
+ wireField: "reasoning_effort",
50
+ wireValue: "none",
51
+ },
52
+ };
53
+ }
54
+ delete body.reasoning_effort;
55
+ body.reasoning = { enabled: false };
56
+ return {
57
+ handled: true,
58
+ reasoningLog: {
59
+ effectiveEffort: "none",
60
+ wireField: "reasoning.enabled",
61
+ wireValue: false,
62
+ },
63
+ };
64
+ }
65
+ if (wireEffort === undefined) return { handled: false };
66
+
67
+ if (nativeOpenAI) {
68
+ delete body.reasoning;
69
+ body.reasoning_effort = wireEffort;
70
+ return {
71
+ handled: true,
72
+ reasoningLog: {
73
+ effectiveEffort: wireEffort,
74
+ wireField: "reasoning_effort",
75
+ wireValue: wireEffort,
76
+ },
77
+ };
78
+ }
79
+ delete body.reasoning_effort;
80
+ body.reasoning = { enabled: true, effort: wireEffort };
81
+ return {
82
+ handled: true,
83
+ reasoningLog: {
84
+ effectiveEffort: wireEffort,
85
+ wireField: "reasoning.effort",
86
+ wireValue: wireEffort,
87
+ },
88
+ };
89
+ }
@@ -13,7 +13,9 @@ import {
13
13
  export const OPENAI_CHAT_IMAGE_BASE64_BUDGET = 3_670_016; // 3.5MiB
14
14
 
15
15
  export interface NormalizeOpenAIChatImagesOptions
16
- extends Pick<NormalizeOptions, "encode" | "tierBias" | "validate"> {}
16
+ extends Pick<NormalizeOptions, "encode" | "tierBias" | "validate"> {
17
+ abortSignal?: AbortSignal;
18
+ }
17
19
 
18
20
  /** Whether `value` is a plain object, so message and part shapes can be walked safely. */
19
21
  function isRecord(value: unknown): value is Record<string, unknown> {
@@ -1,4 +1,6 @@
1
1
  import { hasShrinkableOpenAIChatImages, normalizeOpenAIChatImages } from "./openai-chat-images";
2
+ import { chatParallelToolCallsWireValue } from "./openai-chat/parallel-tool-calls";
3
+ import { applyExplicitChatReasoningWirePolicy } from "./openai-chat/reasoning-wire";
2
4
  import type { AdapterRequest, IncomingMeta, ProviderAdapter } from "./base";
3
5
  import type { AdapterEvent, OcxParsedRequest, OcxProviderConfig, OcxUsage } from "../types";
4
6
  import { modelInList } from "../types";
@@ -40,7 +42,7 @@ import {
40
42
  } from "./openai-chat/errors";
41
43
  import { messagesToChatFormat } from "./openai-chat/messages";
42
44
  import { withOpenAIChatToolNames } from "./openai-chat/tool-name-registry";
43
- import { isNativeOpenAIChatTarget, openAIChatTransport, stripBracketedModelSuffix } from "./openai-chat/wire";
45
+ import { openAIChatTransport, stripBracketedModelSuffix } from "./openai-chat/wire";
44
46
  import { toolChoiceToChatFormat, toolsToChatFormatForProvider } from "./openai-chat/tool-schema";
45
47
 
46
48
  export { stripBracketedModelSuffix } from "./openai-chat/wire";
@@ -142,51 +144,21 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
142
144
  }
143
145
  if (parsed.options.stopSequences !== undefined) body.stop = parsed.options.stopSequences;
144
146
  const reasoningDisabled = modelInList(provider.noReasoningModels, parsed.modelId);
145
- // Some gateways accept a reasoning-effort field on a plain turn but reject the
146
- // effort + tools combination. `noReasoningModels` would fix that only by
147
- // stripping reasoning everywhere, costing the model its whole picker. This keeps
148
- // the ladder advertised and drops the wire field for tool-bearing requests only.
149
- const omitReasoningEffortWithTools = !!tools
150
- && modelInList(provider.omitReasoningEffortWithToolsModels, parsed.modelId);
151
- const reasoningEffort = omitReasoningEffortWithTools
152
- ? undefined
153
- : mapReasoningEffort(provider, parsed.modelId, parsed.options.reasoning);
154
- const nativeOpenAI = isNativeOpenAIChatTarget(provider);
147
+ const reasoningEffort = mapReasoningEffort(provider, parsed.modelId, parsed.options.reasoning);
148
+ const explicitReasoning = applyExplicitChatReasoningWirePolicy({
149
+ provider,
150
+ modelId: parsed.modelId,
151
+ hasTools: !!tools,
152
+ requestedEffort: parsed.options.reasoning,
153
+ wireEffort: reasoningEffort,
154
+ reasoningDisabled,
155
+ body,
156
+ });
155
157
  let reasoningLog: AdapterRequest["reasoningLog"];
156
- if (!reasoningDisabled && !omitReasoningEffortWithTools && provider.reasoningWireFormat === "gateway-object" && parsed.options.reasoning === "none") {
157
- if (nativeOpenAI) {
158
- body.reasoning_effort = "none";
159
- reasoningLog = {
160
- effectiveEffort: "none",
161
- wireField: "reasoning_effort",
162
- wireValue: "none",
163
- };
164
- } else {
165
- body.reasoning = { enabled: false };
166
- reasoningLog = {
167
- effectiveEffort: "none",
168
- wireField: "reasoning.enabled",
169
- wireValue: false,
170
- };
171
- }
158
+ if (explicitReasoning.handled) {
159
+ reasoningLog = explicitReasoning.reasoningLog;
172
160
  } else if (reasoningEffort !== undefined) {
173
- if (provider.reasoningWireFormat === "gateway-object") {
174
- if (nativeOpenAI) {
175
- body.reasoning_effort = reasoningEffort;
176
- reasoningLog = {
177
- effectiveEffort: reasoningEffort,
178
- wireField: "reasoning_effort",
179
- wireValue: reasoningEffort,
180
- };
181
- } else {
182
- body.reasoning = { enabled: true, effort: reasoningEffort };
183
- reasoningLog = {
184
- effectiveEffort: reasoningEffort,
185
- wireField: "reasoning.effort",
186
- wireValue: reasoningEffort,
187
- };
188
- }
189
- } else if (modelInList(provider.thinkingBudgetModels, parsed.modelId)) {
161
+ if (modelInList(provider.thinkingBudgetModels, parsed.modelId)) {
190
162
  const budget = thinkingBudgetForEffort(parsed, reasoningEffort, maxTokens);
191
163
  if (budget !== undefined) {
192
164
  body.thinking_budget = budget;
@@ -249,19 +221,8 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
249
221
  }
250
222
 
251
223
  if (tools) {
252
- if (provider.parallelToolCalls === false) {
253
- // NIM documents the Boolean defaulting to false and kimi rejects true; pin the
254
- // wire bit so Codex cannot opt in via request.options. Other opted-out providers
255
- // omit the field by default so strict OpenAI-compatible hosts never see an
256
- // unsupported knob, but a self-hosted gateway that DOES honor the field and keeps
257
- // emitting parallel calls without it can opt in via pinParallelToolCallsFalse.
258
- if (provider.baseUrl === "https://integrate.api.nvidia.com/v1"
259
- || provider.pinParallelToolCallsFalse === true) {
260
- body.parallel_tool_calls = false;
261
- }
262
- } else if (provider.parallelToolCalls === true) {
263
- body.parallel_tool_calls = parsed.options.parallelToolCalls !== false;
264
- }
224
+ const parallelToolCalls = chatParallelToolCallsWireValue(provider, parsed.options.parallelToolCalls);
225
+ if (parallelToolCalls !== undefined) body.parallel_tool_calls = parallelToolCalls;
265
226
  }
266
227
  if (parsed.stream) body.stream_options = { include_usage: true };
267
228
 
@@ -297,7 +258,11 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
297
258
  };
298
259
  };
299
260
  if (hasShrinkableOpenAIChatImages(messages)) {
300
- return normalizeOpenAIChatImages(messages, { tierBias: incoming?.imageTierBias }).then(finish, finish);
261
+ const imageOptions = { tierBias: incoming?.imageTierBias, abortSignal: incoming?.abortSignal };
262
+ return normalizeOpenAIChatImages(messages, imageOptions).then(finish, error => {
263
+ if (incoming?.abortSignal?.aborted) throw error;
264
+ return finish();
265
+ });
301
266
  }
302
267
  return finish();
303
268
  },
@@ -101,14 +101,17 @@ export function preferConfiguredHostedTools(
101
101
  }
102
102
 
103
103
  let input = body.input;
104
- const strippedAdditionalToolsIndices = new Set<number>();
104
+ // Indices arrive in increasing order, so the first stripped container is already
105
+ // the minimum — tracking it directly avoids spreading an attacker-sized Set into
106
+ // Math.min's argument list.
107
+ let firstStrippedAdditionalToolsIndex: number | undefined;
105
108
  if (Array.isArray(body.input)) {
106
109
  let nestedChanged = false;
107
110
  const mappedInput = body.input.map((item, index) => {
108
111
  if (!isPlainObject(item) || item.type !== "additional_tools" || !Array.isArray(item.tools)) return item;
109
112
  const nestedTools = stripGroup(item.tools);
110
113
  if (nestedTools === item.tools) return item;
111
- strippedAdditionalToolsIndices.add(index);
114
+ firstStrippedAdditionalToolsIndex ??= index;
112
115
  nestedChanged = true;
113
116
  return { ...item, tools: nestedTools };
114
117
  });
@@ -127,17 +130,16 @@ export function preferConfiguredHostedTools(
127
130
  || (Array.isArray(input) && input.some(item => isPlainObject(item)
128
131
  && item.type === "additional_tools"
129
132
  && hasHostedImageGenTool(item.tools)));
130
- if ((strippedTopLevelImageGenTool || strippedAdditionalToolsIndices.size > 0) && !hasHostedImageGenDeclaration) {
133
+ if ((strippedTopLevelImageGenTool || firstStrippedAdditionalToolsIndex !== undefined) && !hasHostedImageGenDeclaration) {
131
134
  if (strippedTopLevelImageGenTool && Array.isArray(tools)) {
132
135
  tools = [...tools, { type: HOSTED_IMAGE_GENERATION_TOOL }];
133
- } else if (strippedAdditionalToolsIndices.size > 0 && Array.isArray(input)) {
136
+ } else if (firstStrippedAdditionalToolsIndex !== undefined && Array.isArray(input)) {
134
137
  // Restore into the FIRST stripped container only. Tool declarations are
135
138
  // request-scoped, not container-scoped — the containers are separate carriers for
136
139
  // one tool set, so a single hosted declaration covers the request. An earlier
137
140
  // revision restored into every stripped container and put `image_generation` on
138
141
  // the wire twice; review caught it.
139
- const firstStripped = Math.min(...strippedAdditionalToolsIndices);
140
- input = input.map((item, index) => index === firstStripped
142
+ input = input.map((item, index) => index === firstStrippedAdditionalToolsIndex
141
143
  && isPlainObject(item)
142
144
  && Array.isArray(item.tools)
143
145
  ? { ...item, tools: [...item.tools, { type: HOSTED_IMAGE_GENERATION_TOOL }] }
@@ -18,6 +18,7 @@ import type { TranslatorBudget } from "../../lib/translator-budget";
18
18
  import { rewriteRoutedCustomToolsForUpstream } from "../../responses/custom-tool-compat";
19
19
  import { rewriteRoutedToolSearchForUpstream } from "../../responses/tool-search-compat";
20
20
  import { rewriteRoutedNamespaceToolsForUpstream } from "../../responses/namespace-tool-compat";
21
+ import { repairLegacyDottedToolCallNames } from "../../responses/legacy-dotted-tool-name-repair";
21
22
  import { preparePlaintextV2AgentMessages } from "../../responses/plaintext-v2-agent-messages";
22
23
  import { isMetaAiResponsesDestination, rewriteMuseToolNamesForUpstream } from "../../responses/muse-tool-name-alias";
23
24
  import { openaiResponsesUrl } from "../openai-responses-url";
@@ -31,7 +32,7 @@ import {
31
32
  import {
32
33
  createAdapterTierMetadata,
33
34
  } from "../../providers/fastwire";
34
- import { mapRoutedResponsesReasoningEffort, normalizeConfiguredReasoningSummaryDelivery, sanitizeReasoningInputContent, stripDisabledReasoningSummaries, stripDisabledVerbosity, stripUnsupportedReasoningSummaryDelivery } from "./reasoning";
35
+ import { dropResponsesReasoningInputItems, mapRoutedResponsesReasoningEffort, normalizeConfiguredReasoningSummaryDelivery, sanitizeReasoningInputContent, stripDisabledReasoningSummaries, stripDisabledVerbosity, stripUnsupportedReasoningSummaryDelivery } from "./reasoning";
35
36
  import { scrubOcxCompactionItems, stripCanonicalOnlyToolFields, stripCanonicalOnlyTopLevelFields, stripInternalChatMessageMetadataPassthrough, stripInvalidItemIds, stripItemIdsWhenUnstored } from "./request-strips";
36
37
  import { stripCanonicalForwardPromptCacheOptions, stripDeprecatedPromptCacheRetention } from "./prompt-cache";
37
38
  import { isPlainObject } from "./internal";
@@ -41,6 +42,7 @@ import { bridgeSearchReplayScope } from "../../responses/bridge-search-replay-ca
41
42
  import { applyTierDecisionToResponsesBody, normalizeCanonicalForwardContinuationEnvelope, normalizeCanonicalForwardPromptEnvelope, stripCanonicalForwardSamplingParams, stripPreviousResponseId, stripStatefulResponsesParams, stripUnsupportedForwardParams } from "./canonical-forward";
42
43
  import { normalizeImageGenClientTools, preferConfiguredHostedTools } from "./image-gen";
43
44
  import { stripMuseSparkUnsupportedWebSearchFields, stripOpenAiOnlyWebSearchFields } from "./web-search";
45
+ import { observeOutbound } from "../../usage/cache-diagnostic";
44
46
 
45
47
  /**
46
48
  * Identifies DeepSeek's strict Responses replay contract: tool-bearing continuations need
@@ -295,6 +297,9 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
295
297
  if (forward || stateless || pairedToolResults) {
296
298
  outBody = repairOrphanedInputItems(outBody, unexpandedMiss, synthesizeMissingCallOutputs);
297
299
  }
300
+ if (provider.dropResponsesReasoningItems === true) {
301
+ outBody = dropResponsesReasoningInputItems(outBody);
302
+ }
298
303
  if (adjacentToolResults) {
299
304
  outBody = normalizeResponsesToolResultAdjacency(outBody);
300
305
  }
@@ -335,6 +340,12 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
335
340
  // every turn, and a strict parser rejects the whole request over the missing key —
336
341
  // `queries` for DeepSeek (#930), `query` for Console Go (#3071).
337
342
  outBody = backfillWebSearchQueries(outBody);
343
+ // #5095: a conversation that already contains a `default.`-prefixed call name is refused by
344
+ // the upstream `^[a-zA-Z0-9_-]+$` name pattern on every later turn that replays it, so the
345
+ // task cannot be compacted or continued at all. Repair the replayed item here, before the
346
+ // canonical-destination split below, because the reported failure was a side chat on a plain
347
+ // OpenAI model inheriting history a routed provider had damaged.
348
+ outBody = repairLegacyDottedToolCallNames(outBody);
338
349
  if (!isCanonicalOpenAiForwardProvider(provider)) {
339
350
  outBody = stripInternalChatMessageMetadataPassthrough(outBody);
340
351
  // The same class of private field, one level up, but keyed on the DESTINATION rather than
@@ -397,14 +408,16 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
397
408
  // Last, so promoted namespace children are also cleared of Codex-private fields.
398
409
  outBody = stripCanonicalOnlyToolFields(outBody, provider.supportsOpenAiWebSearchToolFields === false);
399
410
  }
400
- if (!forward) outBody = normalizeOpenCodeGoAdditionalTools(outBody, url);
411
+ if (!forward) {
412
+ outBody = normalizeOpenCodeGoAdditionalTools(outBody, url, parsed._replayPrefixLen);
413
+ }
401
414
  // Same predicate as the routedCompaction gate in handleResponses(): an authMode check would
402
415
  // let a noncanonical custom forward provider skip this rewrite while the server still routes
403
416
  // it as a summarizer turn (#422). The compaction body build removes the tool surface and must
404
417
  // therefore be the last routed transform that may depend on those declarations. Structural
405
418
  // sanitizers below can still run after it.
406
419
  outBody = normalizeResponsesCodeMode(outBody, parsed, provider);
407
- if (parsed._compactionRequest === true && !isCanonicalOpenAiForwardProvider(provider)) {
420
+ if (parsed._compactionRequest === true && (!isCanonicalOpenAiForwardProvider(provider) || parsed._portableCompaction === true)) {
408
421
  outBody = buildRoutedCompactionBody(outBody);
409
422
  }
410
423
  // Run after routed compaction so nested input_image parts are replaced before a malformed
@@ -489,6 +502,7 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
489
502
  // here, on the serialized body, not on the parsed selector. One place covers both the
490
503
  // HTTP and the WebSocket outbound, because the WS path transports this same request
491
504
  // instead of rebuilding it.
505
+ observeOutbound(parsed._rawBody, finalBody, headers);
492
506
  const body = JSON.stringify(finalBody);
493
507
  const releaseBodyObservation = translatorBudget.observeExternallyCapped(
494
508
  "passthrough_serialization",
@@ -4,6 +4,13 @@ import { OCX_REASONING_PREFIX } from "../../responses/reasoning-envelope";
4
4
  import { configuredReasoningEfforts, mapReasoningEffort, modelRecordValue } from "../../reasoning-effort";
5
5
  import { isPlainObject } from "./internal";
6
6
 
7
+ /** Drop only replayed Responses reasoning items; all other continuation input stays untouched. */
8
+ export function dropResponsesReasoningInputItems(body: unknown): unknown {
9
+ if (!isPlainObject(body) || !Array.isArray(body.input)) return body;
10
+ const input = body.input.filter(item => !isPlainObject(item) || item.type !== "reasoning");
11
+ return input.length === body.input.length ? body : { ...body, input };
12
+ }
13
+
7
14
  /**
8
15
  * Sanitize reasoning input by field policy, not by preserving each item's shape. Retaining a
9
16
  * native `encrypted_content` guarantees only that blob value: `status` is always removed;
@@ -3,7 +3,11 @@ function isRecord(value: unknown): value is Record<string, unknown> {
3
3
  }
4
4
 
5
5
  /** Console Go accepts public tools but rejects the private additional_tools input wrapper. */
6
- export function normalizeOpenCodeGoAdditionalTools(body: unknown, responseUrl: string): unknown {
6
+ export function normalizeOpenCodeGoAdditionalTools(
7
+ body: unknown,
8
+ responseUrl: string,
9
+ replayPrefixLength = 0,
10
+ ): unknown {
7
11
  let destination: URL;
8
12
  try {
9
13
  destination = new URL(responseUrl);
@@ -20,10 +24,16 @@ export function normalizeOpenCodeGoAdditionalTools(body: unknown, responseUrl: s
20
24
 
21
25
  const input: unknown[] = [];
22
26
  const promoted: unknown[] = [];
27
+ const currentTurnStart = Number.isFinite(replayPrefixLength)
28
+ ? Math.min(body.input.length, Math.max(0, Math.trunc(replayPrefixLength)))
29
+ : 0;
23
30
  let changed = false;
24
- for (const item of body.input) {
31
+ for (const [index, item] of body.input.entries()) {
25
32
  if (isRecord(item) && item.type === "additional_tools" && Array.isArray(item.tools)) {
26
33
  changed = true;
34
+ // Replayed wrappers are conversation history, not authority for the current request.
35
+ // Go cannot accept the wrapper itself, so remove it without promoting its catalog.
36
+ if (index < currentTurnStart) continue;
27
37
  // Custom/search/namespace lowering already owns identity and deduplication. This pass
28
38
  // only moves declarations, including hosted tools that intentionally have no name.
29
39
  for (const tool of item.tools) promoted.push(tool);
@@ -181,8 +181,9 @@ export function createRegisteredAdapter(
181
181
  const definition = getAdapterDefinition(provider.adapter);
182
182
  if (!definition) throw new Error(`Unknown adapter: ${provider.adapter}`);
183
183
  const adapter = definition.create(provider, context);
184
- if (effectiveAdapterContract(provider.adapter).wire !== "openai-responses") {
185
- withInputMediaGuard(adapter);
184
+ const wire = effectiveAdapterContract(provider.adapter).wire;
185
+ if (wire !== "openai-responses") {
186
+ withInputMediaGuard(adapter, wire);
186
187
  }
187
188
  const buildRequest = adapter.buildRequest.bind(adapter);
188
189
  adapter.buildRequest = (parsed, incoming) => {