@bitkyc08/opencodex 2.58.0 → 2.60.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 (303) hide show
  1. package/README.md +28 -10
  2. package/gui/dist/assets/index-BTuCbqQd.css +1 -0
  3. package/gui/dist/assets/index-DoBVdPHP.js +134 -0
  4. package/gui/dist/index.html +2 -2
  5. package/gui/dist/provider-icons/crusoe.svg +1 -0
  6. package/gui/dist/provider-icons/opper.svg +3 -0
  7. package/package.json +4 -1
  8. package/src/adapters/anthropic-image-codec.ts +16 -2
  9. package/src/adapters/anthropic-image-normalize.ts +49 -2
  10. package/src/adapters/anthropic.ts +4 -1
  11. package/src/adapters/base.ts +34 -1
  12. package/src/adapters/coding-agent/turn.ts +22 -2
  13. package/src/adapters/command-code.ts +50 -3
  14. package/src/adapters/cursor/catalog.ts +11 -0
  15. package/src/adapters/cursor/checkpoint-store.ts +3 -0
  16. package/src/adapters/cursor/discovery.ts +11 -8
  17. package/src/adapters/cursor/effort-map.ts +16 -2
  18. package/src/adapters/cursor/envelope-echo.ts +55 -2
  19. package/src/adapters/cursor/live-transport.ts +26 -9
  20. package/src/adapters/cursor/message-mapper.ts +3 -2
  21. package/src/adapters/cursor/protobuf-request.ts +8 -5
  22. package/src/adapters/cursor/request-builder.ts +21 -4
  23. package/src/adapters/cursor/thread-continuity.ts +105 -31
  24. package/src/adapters/cursor/tool-guidance.ts +5 -4
  25. package/src/adapters/cursor/transport.ts +19 -0
  26. package/src/adapters/cursor.ts +45 -2
  27. package/src/adapters/devin/cloud-direct/chat.ts +14 -3
  28. package/src/adapters/devin/cloud-direct/index.ts +7 -0
  29. package/src/adapters/devin/cloud-direct/stated-reset-retry.ts +140 -0
  30. package/src/adapters/devin.ts +125 -26
  31. package/src/adapters/google-antigravity-replay.ts +1 -1
  32. package/src/adapters/google-antigravity-wire.ts +55 -4
  33. package/src/adapters/google-http.ts +57 -11
  34. package/src/adapters/google-tool-schema.ts +595 -31
  35. package/src/adapters/google-wire-compiler.ts +93 -10
  36. package/src/adapters/google-wire-shape.ts +461 -0
  37. package/src/adapters/google.ts +60 -10
  38. package/src/adapters/openai-chat/response-events.ts +61 -0
  39. package/src/adapters/openai-chat-images.ts +3 -1
  40. package/src/adapters/openai-chat.ts +10 -11
  41. package/src/adapters/openai-responses/image-gen.ts +8 -6
  42. package/src/adapters/openai-responses/passthrough.ts +25 -4
  43. package/src/adapters/openai-responses/reasoning.ts +7 -0
  44. package/src/adapters/openai-responses/tool-output-recovery.ts +75 -0
  45. package/src/adapters/openai-responses/tool-schema.ts +19 -7
  46. package/src/adapters/opencode-go-additional-tools.ts +12 -2
  47. package/src/adapters/responses-tool-schema.ts +76 -46
  48. package/src/adapters/run-turn-queue.ts +17 -4
  49. package/src/bridge/response-json.ts +1 -1
  50. package/src/bridge/sse.ts +28 -35
  51. package/src/claude/context-windows.ts +22 -0
  52. package/src/claude/outbound.ts +35 -4
  53. package/src/cli/account-api.ts +4 -3
  54. package/src/cli/account-extended.ts +26 -6
  55. package/src/cli/account-orca-import.ts +63 -0
  56. package/src/cli/account.ts +32 -4
  57. package/src/cli/capabilities.ts +40 -0
  58. package/src/cli/claude.ts +29 -1
  59. package/src/cli/codex-cli-update.ts +97 -2
  60. package/src/cli/dispatch.ts +57 -3
  61. package/src/cli/doctor.ts +218 -4
  62. package/src/cli/help.ts +4 -1
  63. package/src/cli/hub.ts +3 -2
  64. package/src/cli/index.ts +95 -22
  65. package/src/cli/models-runtime.ts +33 -4
  66. package/src/cli/opencode.ts +2 -2
  67. package/src/cli/provider.ts +13 -1
  68. package/src/cli/registry.ts +11 -1
  69. package/src/cli/runtime-api.ts +44 -0
  70. package/src/cli/start-args.ts +94 -0
  71. package/src/cli/system-command.ts +2 -0
  72. package/src/client/machine-api.ts +6 -5
  73. package/src/client/machine-listener.ts +16 -3
  74. package/src/client/runtime.ts +26 -2
  75. package/src/clients/config-export/constants.ts +2 -3
  76. package/src/clients/config-export.ts +5 -5
  77. package/src/codex/account-store.ts +146 -5
  78. package/src/codex/auth-api/account-list.ts +19 -11
  79. package/src/codex/auth-api/pool-quota-probe.ts +44 -10
  80. package/src/codex/auth-api/routes.ts +17 -2
  81. package/src/codex/auth-context.ts +16 -12
  82. package/src/codex/catalog/build-entries.ts +25 -4
  83. package/src/codex/catalog/derive-entry.ts +8 -1
  84. package/src/codex/catalog/effort.ts +10 -6
  85. package/src/codex/catalog/gather-capture.ts +22 -2
  86. package/src/codex/catalog/model-hints.ts +66 -33
  87. package/src/codex/catalog/parsing.ts +90 -5
  88. package/src/codex/catalog/provider-models.ts +19 -2
  89. package/src/codex/catalog/reserve-warn.ts +96 -0
  90. package/src/codex/catalog/retained-sync.ts +41 -26
  91. package/src/codex/catalog/routed-gather.ts +61 -3
  92. package/src/codex/cli-installation-identity.ts +210 -0
  93. package/src/codex/cli-installation-targets.ts +158 -0
  94. package/src/codex/context-compat.ts +5 -2
  95. package/src/codex/convergence.ts +5 -0
  96. package/src/codex/desired-state.ts +4 -1
  97. package/src/codex/history-job.ts +6 -6
  98. package/src/codex/history-provider.ts +24 -167
  99. package/src/codex/history-rollout-read.ts +174 -0
  100. package/src/codex/history-state-open.ts +105 -0
  101. package/src/codex/inject/config-toml.ts +44 -2
  102. package/src/codex/inject.ts +3 -2
  103. package/src/codex/internal/catalog-writer.ts +33 -1
  104. package/src/codex/lineage.ts +83 -32
  105. package/src/codex/loopback-target.ts +31 -0
  106. package/src/codex/main-account-hard-lock.ts +2 -1
  107. package/src/codex/main-account.ts +10 -3
  108. package/src/codex/main-device-reauth.ts +17 -9
  109. package/src/codex/model-cache.ts +47 -0
  110. package/src/codex/model-entitlements.ts +80 -2
  111. package/src/codex/observed-model-denials.ts +230 -0
  112. package/src/codex/orca-auth-source.ts +94 -0
  113. package/src/codex/orca-import.ts +219 -0
  114. package/src/codex/prompt-text-probe.ts +289 -16
  115. package/src/codex/quota-401-recovery.ts +12 -0
  116. package/src/codex/quota-types.ts +65 -0
  117. package/src/codex/quota.ts +24 -19
  118. package/src/codex/routing/cooldown-math.ts +8 -47
  119. package/src/codex/routing/pin-drain.ts +57 -0
  120. package/src/codex/routing.ts +20 -16
  121. package/src/codex/shim.ts +1 -1
  122. package/src/codex/subagent-model-fallback.ts +114 -2
  123. package/src/codex/windows-installation-files.ts +224 -0
  124. package/src/combos/failover.ts +125 -5
  125. package/src/config/admitted-identity.ts +222 -0
  126. package/src/config/diagnostics.ts +43 -1
  127. package/src/config/feature-flags.ts +5 -0
  128. package/src/config/load-degrade.ts +33 -0
  129. package/src/config/pending-teardown.ts +8 -0
  130. package/src/config/process-state.ts +36 -3
  131. package/src/config/provider-relative-send-path.ts +16 -0
  132. package/src/config/proxy-env.ts +31 -7
  133. package/src/config/schema/compaction-triggers.ts +11 -0
  134. package/src/config/schema/config-schema.ts +25 -0
  135. package/src/config/schema/leaf-validators.ts +76 -17
  136. package/src/config.ts +2 -2
  137. package/src/generated/compatibility-version.json +410 -258
  138. package/src/generated/model-metadata.ts +1 -1
  139. package/src/grok/reset-coupons.ts +38 -19
  140. package/src/images/loop.ts +6 -1
  141. package/src/integrations/aside-profile-context.ts +37 -3
  142. package/src/integrations/aside-profile-journal.ts +68 -3
  143. package/src/integrations/aside-profiles.ts +128 -3
  144. package/src/integrations/mutation-plan.ts +815 -0
  145. package/src/integrations/writer.ts +85 -99
  146. package/src/lab/live/transport.ts +4 -0
  147. package/src/lab/live/types.ts +5 -0
  148. package/src/lab/subject/behavior-fingerprint.ts +1 -1
  149. package/src/lib/admin-secrets.ts +9 -1
  150. package/src/lib/bounded-body.ts +4 -2
  151. package/src/lib/debug-log-buffer.ts +6 -1
  152. package/src/lib/debug.ts +23 -0
  153. package/src/lib/destination-policy.ts +48 -6
  154. package/src/lib/errors.ts +82 -15
  155. package/src/lib/http-response-semantics.ts +57 -0
  156. package/src/lib/lab-live-pinned-sender.ts +26 -12
  157. package/src/lib/local-destinations.ts +32 -5
  158. package/src/lib/pinned-http.ts +142 -2
  159. package/src/lib/plain-data.ts +103 -0
  160. package/src/lib/process-control.ts +13 -5
  161. package/src/lib/provider-outbound.ts +53 -5
  162. package/src/lib/proxy-env.ts +70 -3
  163. package/src/lib/request-execution-budget.ts +11 -3
  164. package/src/lib/response-body-inactivity.ts +193 -0
  165. package/src/lib/retry-delay.ts +69 -0
  166. package/src/lib/socks5-fetch.ts +741 -0
  167. package/src/lib/spend-ledger-owner.ts +364 -0
  168. package/src/lib/spend-reservation-ledger.ts +332 -35
  169. package/src/lib/windows-system-proxy.ts +16 -11
  170. package/src/lib/workflow-budget.ts +145 -8
  171. package/src/oauth/account-quota-rank.ts +72 -15
  172. package/src/oauth/callback-server.ts +4 -3
  173. package/src/oauth/generic-account-failover.ts +41 -27
  174. package/src/oauth/health.ts +12 -1
  175. package/src/oauth/index.ts +3 -107
  176. package/src/oauth/login-flow-state.ts +127 -0
  177. package/src/oauth/orcarouter.ts +15 -2
  178. package/src/oauth/store.ts +8 -0
  179. package/src/providers/codex-capacity.ts +9 -0
  180. package/src/providers/derive.ts +34 -17
  181. package/src/providers/devin-cli-authmode-migration.ts +14 -10
  182. package/src/providers/devin-provider-merge-migration.ts +33 -12
  183. package/src/providers/free-directory.ts +20 -2
  184. package/src/providers/key-failover.ts +327 -25
  185. package/src/providers/model-rename-migration.ts +56 -1
  186. package/src/providers/model-rename-startup.ts +7 -5
  187. package/src/providers/openai-sidecar.ts +4 -0
  188. package/src/providers/openai-virtual-models.ts +42 -2
  189. package/src/providers/opencode-go-transport.ts +14 -5
  190. package/src/providers/quota/antigravity.ts +22 -2
  191. package/src/providers/quota/report-cache.ts +3 -0
  192. package/src/providers/quota/vendor-probes-key.ts +1 -1
  193. package/src/providers/registry/entries-core.ts +39 -17
  194. package/src/providers/registry/entries-extended.ts +131 -1
  195. package/src/providers/registry/model-ids.ts +168 -0
  196. package/src/providers/registry/model-seeds.ts +87 -21
  197. package/src/providers/registry/types.ts +2 -0
  198. package/src/providers/resolved-model-policy-merge.ts +167 -0
  199. package/src/providers/resolved-model-policy.ts +406 -0
  200. package/src/providers/stale-vision-classification-migration.ts +137 -0
  201. package/src/responses/apply-patch-envelope.ts +32 -11
  202. package/src/responses/bridge-search-replay-cache.ts +152 -0
  203. package/src/responses/code-mode-helper-compat.ts +26 -16
  204. package/src/responses/custom-tool-compat.ts +1 -1
  205. package/src/responses/freeform-wrapper-scan.ts +279 -0
  206. package/src/responses/hosted-tool-policy.ts +85 -2
  207. package/src/responses/legacy-dotted-tool-name-repair.ts +134 -0
  208. package/src/responses/progressive-freeform-input.ts +130 -0
  209. package/src/responses/reasoning-envelope.ts +30 -0
  210. package/src/responses/schema.ts +9 -2
  211. package/src/responses/state.ts +5 -12
  212. package/src/responses/tool-name-aliases.ts +15 -1
  213. package/src/router.ts +91 -115
  214. package/src/routing/compatibility/behavior.ts +9 -0
  215. package/src/routing/compatibility/subject.ts +16 -1
  216. package/src/server/adapter-resolve.ts +9 -0
  217. package/src/server/auth-cors.ts +29 -0
  218. package/src/server/chat-completions.ts +13 -5
  219. package/src/server/chat-native-sse.ts +26 -9
  220. package/src/server/chat-native.ts +10 -4
  221. package/src/server/claude-messages.ts +30 -5
  222. package/src/server/effort-row.ts +11 -3
  223. package/src/server/grok-responses-control-frame.ts +160 -1
  224. package/src/server/gui-static.ts +36 -2
  225. package/src/server/inbound-body-admission.ts +187 -0
  226. package/src/server/index/serve-options.ts +86 -29
  227. package/src/server/index/spend-ledger-lifecycle.ts +66 -0
  228. package/src/server/index/websocket-handler.ts +6 -1
  229. package/src/server/index.ts +24 -25
  230. package/src/server/management/api-access.ts +3 -4
  231. package/src/server/management/aside-profile-routes.ts +266 -7
  232. package/src/server/management/config-routes.ts +48 -7
  233. package/src/server/management/context.ts +3 -0
  234. package/src/server/management/integration-routes.ts +287 -5
  235. package/src/server/management/metrics-routes.ts +20 -0
  236. package/src/server/management/model-rows.ts +224 -12
  237. package/src/server/management/provider-capability-config.ts +35 -7
  238. package/src/server/management/provider-routes.ts +70 -18
  239. package/src/server/management/route-registry.ts +14 -0
  240. package/src/server/management/shared.ts +10 -3
  241. package/src/server/management/system-restart.ts +7 -2
  242. package/src/server/management/system-routes.ts +2 -0
  243. package/src/server/management/usage-aggregate-cache.ts +4 -0
  244. package/src/server/management-api.ts +2 -0
  245. package/src/server/management-auth.ts +15 -1
  246. package/src/server/proxy-liveness.ts +97 -2
  247. package/src/server/readiness.ts +29 -10
  248. package/src/server/relay-eager.ts +24 -2
  249. package/src/server/relay.ts +136 -34
  250. package/src/server/request-log.ts +80 -3
  251. package/src/server/request-metrics.ts +236 -0
  252. package/src/server/responses/adapter-continuation.ts +74 -30
  253. package/src/server/responses/adapter-delivery.ts +39 -8
  254. package/src/server/responses/adapter-dispatch.ts +63 -30
  255. package/src/server/responses/compact.ts +89 -18
  256. package/src/server/responses/compaction-routing.ts +111 -0
  257. package/src/server/responses/core-codex-account.ts +90 -24
  258. package/src/server/responses/core-combo.ts +7 -7
  259. package/src/server/responses/core-normalize.ts +16 -15
  260. package/src/server/responses/core-opaque-recovery.ts +1 -0
  261. package/src/server/responses/core-options.ts +4 -0
  262. package/src/server/responses/encrypted-payload.ts +20 -2
  263. package/src/server/responses/fetch-helpers.ts +68 -2
  264. package/src/server/responses/passthrough-delivery.ts +41 -15
  265. package/src/server/responses/passthrough-dispatch.ts +145 -53
  266. package/src/server/responses/passthrough-execution.ts +11 -1
  267. package/src/server/responses/policy-fallback.ts +5 -13
  268. package/src/server/responses/request-prepare.ts +96 -17
  269. package/src/server/responses/request-send-budget.ts +89 -8
  270. package/src/server/responses/request-sidecar-auth.ts +17 -9
  271. package/src/server/responses/request-spend.ts +38 -9
  272. package/src/server/responses/request-transport.ts +15 -12
  273. package/src/server/responses/run-turn-execution.ts +45 -8
  274. package/src/server/responses/sidecar-execution.ts +19 -2
  275. package/src/server/responses/ws-upstream.ts +16 -28
  276. package/src/server/responses-custom-tool-repair.ts +29 -56
  277. package/src/server/responses-undeclared-tool-guard.ts +31 -1
  278. package/src/server/sse-frame-buffer.ts +12 -10
  279. package/src/server/sse-payload-rewrite.ts +37 -10
  280. package/src/server/system-env-shell.ts +5 -1
  281. package/src/server/system-env.ts +7 -1
  282. package/src/server/workflow-refusal.ts +56 -2
  283. package/src/service/cli.ts +16 -6
  284. package/src/service/guards.ts +10 -0
  285. package/src/service/health.ts +43 -0
  286. package/src/service/state.ts +7 -2
  287. package/src/tray/windows-tray.ps1 +155 -3
  288. package/src/types/accounts.ts +4 -0
  289. package/src/types/config.ts +111 -6
  290. package/src/types/provider.ts +37 -0
  291. package/src/types/request.ts +9 -1
  292. package/src/types/tools.ts +14 -0
  293. package/src/types/wire.ts +9 -1
  294. package/src/types.ts +1 -0
  295. package/src/usage/expected-prices.ts +28 -0
  296. package/src/usage/log.ts +87 -4
  297. package/src/vision/eligibility.ts +88 -9
  298. package/src/vision/plan.ts +34 -10
  299. package/src/web-search/executor.ts +41 -2
  300. package/src/web-search/loop.ts +6 -1
  301. package/src/web-search/passthrough-bridge.ts +39 -5
  302. package/gui/dist/assets/index-BbrHOIY0.js +0 -128
  303. package/gui/dist/assets/index-C5-RdDmD.css +0 -1
@@ -177,6 +177,15 @@ export const META_MUSE_REASONING_EFFORTS = ["minimal", "low", "medium", "high",
177
177
  export const META_MUSE_REASONING_EFFORT_MAP: Record<string, string> = Object.fromEntries(
178
178
  META_MUSE_REASONING_EFFORTS.map(effort => [effort, effort]),
179
179
  );
180
+ /*
181
+ * Muse Code credentials have a separate capability contract. Meta's authenticated
182
+ * /muse-code/models roster advertises max for both 1.3 models, and the Responses API
183
+ * accepts it when the request identifies the Muse client surface.
184
+ */
185
+ export const META_MUSE_CODE_REASONING_EFFORTS = [...META_MUSE_REASONING_EFFORTS, "max"];
186
+ export const META_MUSE_CODE_REASONING_EFFORT_MAP: Record<string, string> = Object.fromEntries(
187
+ META_MUSE_CODE_REASONING_EFFORTS.map(effort => [effort, effort]),
188
+ );
180
189
  /** Both Muse Spark 1.3 tiers publish a 1,048,576-token window (dev.meta.ai/docs/models). */
181
190
  export const META_MUSE_CONTEXT_WINDOW = 1_048_576;
182
191
  export const META_MUSE_MODELS = ["muse-spark-1.3", "muse-spark-1.3-contributor"];
@@ -315,6 +324,13 @@ export const DEEPSEEK_VISION_PREVIEW_MODEL = "deepseek-v4-flash-vision-exp";
315
324
  */
316
325
  export const COMMAND_CODE_IMAGE_MODELS = [
317
326
  `deepseek/${DEEPSEEK_VISION_PREVIEW_MODEL}`,
327
+ // Probed 2026-09-18 through a running 2.58.0 proxy: a 3x3 random-color grid
328
+ // (180x180 PNG, six candidate colors) came back 9/9 correct both as a user
329
+ // message and as a tool_result, and the request logs show the route served
330
+ // the image natively — no vision-sidecar call in either window. #4505 asked
331
+ // for exactly this upstream probe before promoting the id. The sibling
332
+ // deepseek/deepseek-v4-flash route remains verified-negative above.
333
+ "deepseek/deepseek-v4.1-flash",
318
334
  "gpt-5.6-luna",
319
335
  "gpt-5.6-sol",
320
336
  "MiniMaxAI/MiniMax-M3",
@@ -334,20 +350,19 @@ export const COMMAND_CODE_IMAGE_MODELS = [
334
350
  /**
335
351
  * Native image stays sourced from COMMAND_CODE_IMAGE_MODELS. Text-only routes
336
352
  * sit beside that list so the catalog can still advertise sidecar coverage
337
- * without claiming the gateway itself accepts a picture.
338
- *
339
- * The gateway-prefixed DeepSeek V4.1 Flash route has no verified native image
340
- * support, so declaring it image-capable would hand it a picture it drops. A
341
- * positive text-only declaration makes it a vision-sidecar consumer
353
+ * without claiming the gateway itself accepts a picture. A positive text-only
354
+ * declaration makes the route a vision-sidecar consumer
342
355
  * (src/vision/eligibility.ts), so the catalog advertises image input on its
343
- * behalf and the four-target combo in #4505 intersects to ["text","image"]
344
- * instead of ["text"] — without claiming native vision. modelInputModalities
345
- * is per-key filled, so this reaches an existing install even when
346
- * noVisionModels was persisted before the id joined that list.
356
+ * behalf — without claiming native vision — and modelInputModalities is
357
+ * per-key filled, so that reaches an existing install even when noVisionModels
358
+ * was persisted before the id joined a list.
359
+ *
360
+ * Empty as of 2026-09-18. Its only entry, deepseek/deepseek-v4.1-flash, moved
361
+ * to COMMAND_CODE_IMAGE_MODELS once the #4505-requested probe passed on both
362
+ * the user-message and tool-result paths (see the note at that entry). The
363
+ * mechanism stays for the next route that measures text-only.
347
364
  */
348
- export const COMMAND_CODE_TEXT_ONLY_MODELS = [
349
- "deepseek/deepseek-v4.1-flash",
350
- ] as const;
365
+ export const COMMAND_CODE_TEXT_ONLY_MODELS = [] as const;
351
366
  export const COMMAND_CODE_MODEL_INPUT_MODALITIES: Record<string, ["text"] | ["text", "image"]> = {
352
367
  ...Object.fromEntries(COMMAND_CODE_IMAGE_MODELS.map(id => [id, ["text", "image"] as ["text", "image"]])),
353
368
  ...Object.fromEntries(COMMAND_CODE_TEXT_ONLY_MODELS.map(id => [id, ["text"] as ["text"]])),
@@ -439,9 +454,15 @@ export const deepseekReasoningMapFor = (modelId: string): Record<string, string>
439
454
  // https://help.aliyun.com/en/model-studio/token-plan-quickstart
440
455
  // 260909 refresh, re-probed against the live gateway (both regions, both tiers):
441
456
  // https://github.com/oliver-mee/alibaba-token-plan-wiki (machine-readable catalog).
442
- // glm-5.3 / glm-5.3-flash removed from both Token Plan catalogs: they exist on Z.AI
443
- // endpoints but the Token Plan gateway has never served either id (the 260826 seed
444
- // propagated them across every GLM-carrying catalog; a selected row 404s).
457
+ // 260918: glm-5.3 returns. The 260909 removal was correct at the time (the id
458
+ // 404'd on every plan key), but the gateway started serving glm-5.3 on 260917:
459
+ // it now appears on /models for global Team, global Personal, and CN Team, and
460
+ // answers a completion on a Personal key (probed 260918). Contract on the plan
461
+ // gateway: effort low/high/max (default max), thinking always-on (the gateway
462
+ // rejects enable_thinking:false with 400), 1M context, 131,072 max output,
463
+ // text-only input, strict json_schema accepted. glm-5.3-flash REMAINS OUT:
464
+ // still never served by the Token Plan gateway (docs.z.ai VLM id, not plan
465
+ // entitlement).
445
466
  // The Beijing preset keeps the Personal Edition subset; non-chat ids (audio/image/
446
467
  // video families) stay out: they answer only on async endpoints openai-chat cannot
447
468
  // reach. deepseek-v4-pro-0813 is callable but NOT listed by /models, which is the
@@ -457,7 +478,7 @@ export const deepseekReasoningMapFor = (modelId: string): Record<string, string>
457
478
  // drifting ones.
458
479
  export const ALIBABA_TOKEN_PLAN_MODELS = [
459
480
  "qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash",
460
- "deepseek-v4-pro", "deepseek-v4-flash-0731", "deepseek-v4.1-flash", "glm-5.2",
481
+ "deepseek-v4-pro", "deepseek-v4-flash-0731", "deepseek-v4.1-flash", "glm-5.2", "glm-5.3",
461
482
  ];
462
483
  export const ALIBABA_TOKEN_PLAN_QWEN_MODELS = [
463
484
  "qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash",
@@ -474,6 +495,7 @@ export const ALIBABA_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
474
495
  // Vision probed on the plan gateway 260915 (user message and tool result, both 200).
475
496
  "deepseek-v4.1-flash": ["text", "image"],
476
497
  "glm-5.2": ["text"],
498
+ "glm-5.3": ["text"],
477
499
  };
478
500
 
479
501
  // 260721 Alibaba Token Plan International (ap-southeast-1 / Singapore, hardened 260721).
@@ -487,7 +509,7 @@ export const ALIBABA_INTL_TOKEN_PLAN_MODELS = [
487
509
  "qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash",
488
510
  "deepseek-v4-pro", "deepseek-v4-pro-0813", "deepseek-v4-flash", "deepseek-v4-flash-0731", "deepseek-v4.1-flash", "deepseek-v3.2",
489
511
  "kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5",
490
- "glm-5.2", "glm-5.1", "glm-5",
512
+ "glm-5.2", "glm-5.3", "glm-5.1", "glm-5",
491
513
  "MiniMax-M2.5",
492
514
  ];
493
515
  export const ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS = [
@@ -589,7 +611,7 @@ export const ALIBABA_TOKEN_PLAN_CONTEXT_WINDOWS: Record<string, number> = {
589
611
  "deepseek-v4-pro": 1_000_000, "deepseek-v4-pro-0813": 1_000_000, "deepseek-v4-flash": 1_000_000,
590
612
  "deepseek-v4-flash-0731": 1_000_000, "deepseek-v4.1-flash": 1_000_000, "deepseek-v3.2": 131_072,
591
613
  "kimi-k2.7-code": 262_144, "kimi-k2.6": 262_144, "kimi-k2.5": 262_144,
592
- "glm-5.2": 1_000_000, "glm-5.1": 202_752, "glm-5": 202_752,
614
+ "glm-5.2": 1_000_000, "glm-5.3": 1_000_000, "glm-5.1": 202_752, "glm-5": 202_752,
593
615
  "MiniMax-M2.5": 196_608,
594
616
  };
595
617
  export const ALIBABA_TOKEN_PLAN_MAX_OUTPUT_TOKENS: Record<string, number> = {
@@ -598,17 +620,17 @@ export const ALIBABA_TOKEN_PLAN_MAX_OUTPUT_TOKENS: Record<string, number> = {
598
620
  "deepseek-v4-pro": 393_216, "deepseek-v4-pro-0813": 393_216, "deepseek-v4-flash": 393_216,
599
621
  "deepseek-v4-flash-0731": 393_216, "deepseek-v4.1-flash": 393_216, "deepseek-v3.2": 65_536,
600
622
  "kimi-k2.7-code": 262_144, "kimi-k2.6": 262_144, "kimi-k2.5": 98_304,
601
- "glm-5.2": 131_072, "glm-5.1": 128_000, "glm-5": 16_384,
623
+ "glm-5.2": 131_072, "glm-5.3": 131_072, "glm-5.1": 128_000, "glm-5": 16_384,
602
624
  "MiniMax-M2.5": 32_768,
603
625
  };
604
626
  export const ALIBABA_TOKEN_PLAN_NO_VISION = [
605
627
  "qwen3.7-max", "deepseek-v4-pro", "deepseek-v4-pro-0813", "deepseek-v4-flash",
606
- "deepseek-v4-flash-0731", "deepseek-v3.2", "glm-5.2", "glm-5.1", "glm-5", "MiniMax-M2.5",
628
+ "deepseek-v4-flash-0731", "deepseek-v3.2", "glm-5.2", "glm-5.3", "glm-5.1", "glm-5", "MiniMax-M2.5",
607
629
  ];
608
630
  export const ALIBABA_TOKEN_PLAN_PRESERVE_REASONING = [
609
631
  "qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash",
610
632
  "deepseek-v4-pro", "deepseek-v4-pro-0813", "deepseek-v4-flash", "deepseek-v4-flash-0731",
611
- "deepseek-v4.1-flash", "glm-5.2",
633
+ "deepseek-v4.1-flash", "glm-5.2", "glm-5.3",
612
634
  ];
613
635
 
614
636
  // 260717 Kimi K3: the subscription endpoint uses one upstream id (`k3`) for both
@@ -960,3 +982,47 @@ export const CLINE_PASS_TEXT_ONLY_MODELS = CLINE_PASS_MODALITY_KNOWN_MODELS.filt
960
982
  export const CLINE_PASS_MODEL_INPUT_MODALITIES: Record<string, string[]> = Object.fromEntries(
961
983
  CLINE_PASS_MODALITY_KNOWN_MODELS.map(id => [id, CLINE_PASS_IMAGE_MODELS.has(id) ? ["text", "image"] : ["text"]]),
962
984
  );
985
+
986
+ // Opper seed: bare *pool* names. A pool is every provider Opper serves that model through; Opper
987
+ // picks the route per request. Each name is the `.model` of a `pooled: true` entry in the public
988
+ // catalogue snapshot supplied by the original provider author
989
+ // (https://api.opper.ai/v3/models?limit=2000, captured 2026-09-14); `vendor/model` ids
990
+ // (anthropic/claude-sonnet-4-6) pin one route and stay valid, they are just not seeded.
991
+ export const OPPER_MODELS = [
992
+ "claude-sonnet-4-6",
993
+ "claude-opus-5",
994
+ "gpt-5.5",
995
+ "gpt-5.4-mini",
996
+ "gemini-3.8-flash",
997
+ "deepseek-v4-pro",
998
+ "kimi-k3",
999
+ "mistral-large-2512",
1000
+ ];
1001
+ // Smallest value across each pool's members in that snapshot, capped at the lab model's own limit
1002
+ // (kimi-k3 output); live discovery owns which models exist.
1003
+ export const OPPER_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
1004
+ "claude-sonnet-4-6": 1_000_000,
1005
+ "claude-opus-5": 1_000_000,
1006
+ "gpt-5.5": 1_050_000,
1007
+ "gpt-5.4-mini": 400_000,
1008
+ "gemini-3.8-flash": 1_048_576,
1009
+ "deepseek-v4-pro": 1_000_000,
1010
+ "kimi-k3": 1_048_576,
1011
+ "mistral-large-2512": 256_000,
1012
+ };
1013
+ export const OPPER_MODEL_MAX_OUTPUT_TOKENS: Record<string, number> = {
1014
+ "claude-sonnet-4-6": 64_000,
1015
+ "claude-opus-5": 128_000,
1016
+ "gpt-5.5": 128_000,
1017
+ "gpt-5.4-mini": 128_000,
1018
+ "gemini-3.8-flash": 65_536,
1019
+ "deepseek-v4-pro": 65_536,
1020
+ "kimi-k3": 131_072,
1021
+ "mistral-large-2512": 8_192,
1022
+ };
1023
+ // Pools whose members do not all accept image input (deepseek-v4-pro: no member does; kimi-k3: the
1024
+ // sference route is text-only), so the shared modality set is text.
1025
+ export const OPPER_TEXT_ONLY_MODELS = ["deepseek-v4-pro", "kimi-k3"];
1026
+ export const OPPER_MODEL_INPUT_MODALITIES: Record<string, string[]> = Object.fromEntries(
1027
+ OPPER_MODELS.map(id => [id, OPPER_TEXT_ONLY_MODELS.includes(id) ? ["text"] : ["text", "image"]]),
1028
+ );
@@ -264,6 +264,8 @@ export interface ProviderRegistryEntry {
264
264
  modelServiceTierCapabilityBaseUrlGuard?: (baseUrl: string) => boolean;
265
265
  /** Registry default for plaintext reasoning replay; see `OcxProviderConfig.preserveResponsesReasoningContent`. Registry-only like `supportsServiceTier`. */
266
266
  preserveResponsesReasoningContent?: boolean;
267
+ /** Registry default for dropping replayed reasoning items for Responses upstreams that reject them. */
268
+ dropResponsesReasoningItems?: boolean;
267
269
  /** Registry defaults for per-model Codex reasoning propagation; explicit user keys win during enrichment. */
268
270
  modelSupportsReasoningSummaries?: Record<string, boolean>;
269
271
  /** Registry defaults for per-model Codex Responses verbosity support. */
@@ -0,0 +1,167 @@
1
+ import type { OcxProviderConfig } from "../types";
2
+ import { MODEL_ADAPTER_OVERRIDE_ALLOWED } from "../types";
3
+ import type { InboundWire, ModelWireDefault, ProviderRegistryEntry } from "./registry/types";
4
+
5
+ export type StaticPolicySource =
6
+ | "operator" | "operator-capability" | "captured-auth"
7
+ | "registry" | "hard-pin" | "provider-default" | "unknown";
8
+
9
+ export function detachedClone<T>(value: T): T {
10
+ if (Array.isArray(value)) return value.map(item => detachedClone(item)) as T;
11
+ if (value && typeof value === "object") {
12
+ return Object.fromEntries(Object.entries(value as Record<string, unknown>)
13
+ .map(([key, nested]) => [key, detachedClone(nested)])) as T;
14
+ }
15
+ return value;
16
+ }
17
+
18
+ export function recursivelyFreeze<T>(value: T): T {
19
+ if (!value || typeof value !== "object" || Object.isFrozen(value)) return value;
20
+ for (const nested of Object.values(value as Record<string, unknown>)) recursivelyFreeze(nested);
21
+ return Object.freeze(value);
22
+ }
23
+
24
+ export function scalar<T>(operator: T | undefined, registry: T | undefined): [T | undefined, StaticPolicySource] {
25
+ if (operator !== undefined) return [detachedClone(operator), "operator"];
26
+ if (registry !== undefined) return [detachedClone(registry), "registry"];
27
+ return [undefined, "unknown"];
28
+ }
29
+
30
+ export function mapFill<T>(
31
+ registry: Readonly<Record<string, T>> | undefined,
32
+ operator: Readonly<Record<string, T>> | undefined,
33
+ ): [Record<string, T> | undefined, StaticPolicySource] {
34
+ if (!registry && !operator) return [undefined, "unknown"];
35
+ return [detachedClone({ ...(registry ?? {}), ...(operator ?? {}) }), operator ? "operator" : "registry"];
36
+ }
37
+
38
+ export function nestedMapFill(
39
+ registry: Readonly<Record<string, Record<string, string>>> | undefined,
40
+ operator: Readonly<Record<string, Record<string, string>>> | undefined,
41
+ ): [Record<string, Record<string, string>> | undefined, StaticPolicySource] {
42
+ if (!registry && !operator) return [undefined, "unknown"];
43
+ const merged: Record<string, Record<string, string>> = {};
44
+ for (const [key, value] of Object.entries(registry ?? {})) merged[key] = { ...value };
45
+ for (const [key, value] of Object.entries(operator ?? {})) {
46
+ merged[key] = { ...(merged[key] ?? {}), ...value };
47
+ }
48
+ return [merged, operator ? "operator" : "registry"];
49
+ }
50
+
51
+ export function positiveCapMap(
52
+ registry: Readonly<Record<string, number>> | undefined,
53
+ operator: Readonly<Record<string, number>> | undefined,
54
+ ): [Record<string, number> | undefined, StaticPolicySource] {
55
+ if (!registry && !operator) return [undefined, "unknown"];
56
+ const merged = { ...(registry ?? {}) };
57
+ for (const [key, value] of Object.entries(operator ?? {})) {
58
+ merged[key] = typeof merged[key] === "number" ? Math.min(merged[key]!, value) : value;
59
+ }
60
+ return [merged, operator ? "operator" : "registry"];
61
+ }
62
+
63
+ export function stableUnion(
64
+ registry: readonly string[] | undefined,
65
+ operator: readonly string[] | undefined,
66
+ ): [string[] | undefined, StaticPolicySource] {
67
+ if (!registry && !operator) return [undefined, "unknown"];
68
+ return [[...new Set([...(registry ?? []), ...(operator ?? [])])], operator ? "operator" : "registry"];
69
+ }
70
+
71
+ export function staticHeaders(
72
+ registry: Readonly<Record<string, string>> | undefined,
73
+ operator: Readonly<Record<string, string>> | undefined,
74
+ ): [Record<string, string> | undefined, StaticPolicySource] {
75
+ if (!registry && !operator) return [undefined, "unknown"];
76
+ if (!registry) return [{ ...(operator ?? {}) }, "operator"];
77
+ if (!operator) return [{ ...registry }, "registry"];
78
+ const claimed = new Set(Object.keys(operator).map(name => name.toLowerCase()));
79
+ const merged: Record<string, string> = { ...operator };
80
+ for (const [name, value] of Object.entries(registry)) {
81
+ if (!claimed.has(name.toLowerCase())) merged[name] = value;
82
+ }
83
+ return [merged, "operator"];
84
+ }
85
+
86
+ export function resolvedBaseUrl(
87
+ entry: Readonly<ProviderRegistryEntry> | undefined,
88
+ provider: Readonly<OcxProviderConfig>,
89
+ ): [string, StaticPolicySource] {
90
+ if (!entry) return [provider.baseUrl, "operator"];
91
+ const configured = typeof provider.baseUrl === "string" ? provider.baseUrl.trim() : "";
92
+ const configuredIsResolved = configured.length > 0 && !/\{[^}]*\}/.test(configured);
93
+ if (entry.allowBaseUrlOverride && !configuredIsResolved) {
94
+ throw new Error(`Invalid baseUrl for provider "${entry.id}": expected a nonblank URL without unresolved placeholders`);
95
+ }
96
+ return (/\{[^}]*\}/.test(entry.baseUrl) || entry.allowBaseUrlOverride) && configuredIsResolved
97
+ ? [configured, "operator"]
98
+ : [entry.baseUrl, "registry"];
99
+ }
100
+
101
+ export function sameStringArray(left: readonly string[] | undefined, right: readonly string[]): boolean {
102
+ return left?.length === right.length && left.every((value, index) => value === right[index]);
103
+ }
104
+
105
+ /** Legacy config-map lookup: exact id, colon family, then case-folded exact id. */
106
+ export function legacyModelValue<T>(record: Readonly<Record<string, T>> | undefined, modelId: string): T | undefined {
107
+ if (!record) return undefined;
108
+ if (Object.hasOwn(record, modelId)) return record[modelId];
109
+ const colon = modelId.indexOf(":");
110
+ if (colon > 0 && Object.hasOwn(record, modelId.slice(0, colon))) return record[modelId.slice(0, colon)];
111
+ const folded = modelId.toLowerCase();
112
+ return Object.entries(record).find(([key]) => key.toLowerCase() === folded)?.[1];
113
+ }
114
+
115
+ /** Provenance from the same merged-key walk as legacyModelValue. */
116
+ export function legacyModelSource<T>(
117
+ operator: Readonly<Record<string, T>> | undefined,
118
+ registry: Readonly<Record<string, T>> | undefined,
119
+ modelId: string,
120
+ ): StaticPolicySource {
121
+ const merged = { ...(registry ?? {}), ...(operator ?? {}) };
122
+ let winningKey: string | undefined;
123
+ if (Object.hasOwn(merged, modelId)) winningKey = modelId;
124
+ const colon = modelId.indexOf(":");
125
+ if (winningKey === undefined && colon > 0 && Object.hasOwn(merged, modelId.slice(0, colon))) {
126
+ winningKey = modelId.slice(0, colon);
127
+ }
128
+ if (winningKey === undefined) {
129
+ const folded = modelId.toLowerCase();
130
+ winningKey = Object.keys(merged).find(key => key.toLowerCase() === folded);
131
+ }
132
+ if (winningKey === undefined) return "unknown";
133
+ return Object.hasOwn(operator ?? {}, winningKey) ? "operator" : "registry";
134
+ }
135
+
136
+ export function anthropicFamilyContextWindow(
137
+ record: Readonly<Record<string, number>> | undefined,
138
+ id: string,
139
+ ): number | undefined {
140
+ if (!record || !id.toLowerCase().startsWith("claude-")) return undefined;
141
+ let candidate = id;
142
+ while (true) {
143
+ const cut = candidate.lastIndexOf("-");
144
+ if (cut <= 0 || !/^\d+$/.test(candidate.slice(cut + 1))) return undefined;
145
+ candidate = candidate.slice(0, cut);
146
+ const value = record[candidate]
147
+ ?? Object.entries(record).find(([key]) => key.toLowerCase() === candidate.toLowerCase())?.[1];
148
+ if (typeof value === "number" && value > 0) return value;
149
+ }
150
+ }
151
+
152
+ export function wireDefault(
153
+ declared: ModelWireDefault | undefined,
154
+ provider: Readonly<OcxProviderConfig>,
155
+ entry: Readonly<ProviderRegistryEntry> | undefined,
156
+ inbound: InboundWire,
157
+ effectiveAuthMode: OcxProviderConfig["authMode"] | undefined,
158
+ ): string | undefined {
159
+ if (declared === undefined || !MODEL_ADAPTER_OVERRIDE_ALLOWED.has(provider.adapter)) return undefined;
160
+ if (typeof declared !== "string") {
161
+ if (!declared.inbound.includes(inbound)) return undefined;
162
+ const authMode = effectiveAuthMode ?? provider.authMode ?? entry?.authKind;
163
+ if (declared.authModes && authMode && !declared.authModes.includes(authMode)) return undefined;
164
+ }
165
+ const wire = typeof declared === "string" ? declared : declared.wire;
166
+ return MODEL_ADAPTER_OVERRIDE_ALLOWED.has(wire) ? wire : undefined;
167
+ }