diff --git a/devlog/_plan/260826_glm53_flash_preseed/000_plan.md b/devlog/_plan/260826_glm53_flash_preseed/000_plan.md new file mode 100644 index 0000000000..f404ca633c --- /dev/null +++ b/devlog/_plan/260826_glm53_flash_preseed/000_plan.md @@ -0,0 +1,150 @@ +# 000 — Seeding `glm-5.3-flash` ahead of the providers that will serve it + +## The ask, and why the codebase already agrees with it + +Put `glm-5.3-flash` everywhere `ox-alpha` or `glm-5.2` already lives, before the +providers announce it. + +That is not a new policy. `src/providers/registry.ts:340-342` states it: + +> The non-Z.AI providers below are speculative on purpose: they carry 5.2 today and are +> expected to pick 5.3 up on their usual lag. Providers whose live `/v1/models` +> discovery is enabled self-correct on the next successful fetch; static ones need a +> follow-up refresh. + +This unit is the same move one generation on. Two facts make it safe: + +- `rg glm-5.3-flash` returns **nothing** today, so there is no duplicate id to collide with. +- `glm-4.7-flash` already sits beside `glm-4.7` in `ZHIPU_BIGMODEL_TEXT_MODELS`, so a + flash sibling next to its full model is an established shape here, not an invention. + +## What `glm-5.3-flash` is + +Z.AI's flash tier for GLM-5.3: 1M context, text-only, cheaper than the full model. Where +a provider needs a number this unit does not have from that provider's own docs, it +**mirrors the `glm-5.3` entry that provider already carries** rather than inventing a +figure. That is stated per-cluster below and is the difference between seeding and guessing. + +## The vision decision, corrected mid-unit + +The first pass put `glm-5.3-flash` into every `noVisionModels` list, reasoning from +`registry.ts:500-506`: + +> Verified-negative and therefore deliberately ABSENT: … zai-org/GLM-5.2, zai-org/GLM-5.3 +> … Those routes accept the request and drop the image, which is worse than declining it. + +**That was wrong, and the same comment says why.** It ends with "Do not add an id here on +family resemblance" — and inheriting a text-only verdict from `glm-5.3` because of the +shared name is that exact error, pointed the other way. + +`glm-5.3-flash` is a vision model. Z.AI documents it under `docs.z.ai/guides/vlm/` — the +VLM namespace, the same one `glm-4.6v` lives in — accepting `image_url` blocks as public +URLs or Base64, multiple images per request, plus video and file input. OpenRouter lists +it as a multimodal reasoning model: 1M context, 128K max output, text + image + video. + +One incidental confirmation: this unit had already given it `ZAI_GLM_53_REASONING_EFFORTS` +(low/high/max), which matches the three-tier ladder OpenRouter documents for it. The +effort ladder was right for the same reason the modality was wrong — 5.3 is its family. + +The naming split is the tell: `-flash` is a speed and price tier; `v` is the modality +suffix. A flash variant of a VLM is still a VLM. + +So it ships with `["text", "image"]` and appears in **no** `noVisionModels` list. + +## Ox Alpha: removed entirely + +The first pass excluded `glm-5.3-flash` from the Ox Alpha surfaces and left Ox Alpha in +place. It is now removed from the tree outright — both ids (`stealth/ox-alpha`, +`openai/ox-alpha`) and the OpenCode Zen slug that served the same stealth model +(`x-preview-f-free`), along with `OX_ALPHA_CONTEXT_WINDOW`, the Command Code effort +profile, the OpenRouter catalog entry, and every comment describing them. + +"Ox Alpha" was a stealth-window model: free, unbranded, and time-boxed by construction. +A catalog entry for a window that has closed advertises something the provider no longer +serves, which is the same class of defect this unit exists to avoid in the other +direction. + +## Insertion points + +Every one of these already carries `glm-5.2`; `glm-5.3-flash` goes in beside `glm-5.3`. + +| # | Location | Symbol | Note | +|---|---|---|---| +| 1 | registry.ts:474 | `ZHIPU_BIGMODEL_TEXT_MODELS` | flash sibling precedent lives here (`glm-4.7-flash`) | +| 2 | registry.ts:480 | `ZHIPU_BIGMODEL_THINKING_TOGGLE_MODELS` | 5.3 is present, so the toggle applies | +| 3 | registry.ts:616 + 627 | `ALIBABA_TOKEN_PLAN_MODELS` + input modalities | `["text"]`, matching its `glm-5.3` | +| 4 | registry.ts:639 | `ALIBABA_INTL_TOKEN_PLAN_MODELS` | + modalities at 854-ish block | +| 5 | registry.ts:689 / 697 / 715 | Volcengine coding / agent / text-only | text-only list too | +| 6 | registry.ts:864 | `NEURALWATT_REASONING_HISTORY_MODELS` | Neuralwatt suffixes its ids; see caution below | +| 7 | registry.ts:944 | baseten list | | +| 8 | registry.ts:952 | `SCALEWAY_SERVERLESS_CHAT_MODELS` | | +| 9 | registry.ts:973 / 982 / 988 | `UMANS_MODELS` + text-only + context | prefix is `umans-` | +| 10 | registry.ts:997 / 1012 | cline-pass | prefix is `cline-pass/` | +| 11 | registry.ts:2201 / 2282 / 2284 | `zai` + `zhipu-bigmodel-coding` provider blocks | context window mirrors 5.3's 1M | +| 12 | registry.ts:2428 / 2464 | alibaba plan context windows | 1M, mirroring 5.3 | +| 13 | registry.ts:2514 / 2517 | ollama-cloud | | +| 14 | registry.ts:2730 | cloudflare `@cf/zai-org/…` | prefix form | + +**Caution on 6 and 11.** Neuralwatt fans each model into `-fast` / `-short` / +`-short-fast` variants and the parity test pins the full list with `toEqual`. Z.AI fans +into `[1m]` aliases with three pinned `toEqual` maps. Adding a bare id to either without +its variants leaves the tables internally inconsistent. This unit adds the **plain +`glm-5.3-flash`** id and does not synthesize `-fast`/`-short`/`[1m]` variants: those +suffixes encode routing behavior those providers documented per model, and inventing +them would assert a product that may not exist. + +## The test surface — this is the real work + +`tests/provider-registry-parity.test.ts` pins exact lists with `toEqual` (17 `glm-5.3` +hits). Every seeded list has a matching assertion that must move in the same commit, or +the suite goes red. Also covering these tables: `volcengine-providers`, +`cline-pass-provider`, `alibaba-intl-token-plan`, `catalog-vision-sidecar-modalities`, +`codex-catalog`, `umans-provider`, `routing-compatibility-model-matching`. + +`src/generated/model-metadata.ts` is **generated** (`scripts/generate-model-metadata.ts`, +"Do not edit by hand") and is NOT touched here. Its data comes from upstream catalogs; it +will pick `glm-5.3-flash` up on the next regeneration once providers publish it. + +## Accept criteria + +## Where a seed actually reaches the user (measured) + +Seeding only matters where the static catalog is what ships. Reading each provider block: + +| Provider | liveModels | modelDiscovery | Seed reaches the user? | +|---|---|---|---| +| `zhipu-bigmodel` | false | no | **yes** — static | +| `alibaba-token-plan` / `-intl` | false | no | **yes** — static | +| `volcengine-coding-plan` / `-agent-plan` | false | no | **yes** — static | +| `neuralwatt` | false | no | **yes** — static | +| `umans` | false | no | **yes** — static | +| `zai` | false | no | **yes** — static | +| `ollama-cloud` | false | no | **yes** — static | +| `zhipu-bigmodel-coding` | true | no | seed is the offline fallback | +| `cline-pass` | true | no | seed is the offline fallback | +| `baseten` | true | yes | overwritten on first successful fetch | +| `scaleway` | true | yes | overwritten on first successful fetch | +| `cloudflare-workers-ai` | true | yes | overwritten on first successful fetch | + +This confirms the claim quoted at the top of this document rather than assuming it: the +static providers are exactly the ones that "need a follow-up refresh", and they are the +majority here. The three discovery-enabled providers still get the id — it is their +documented offline fallback, and a wrong-but-harmless entry there is replaced the moment +a real fetch succeeds. + +| # | Criterion | Evidence | +|---|---|---| +| 1 | Every `glm-5.2` provider list also carries `glm-5.3-flash` | `rg` shows the pair per cluster | +| 2 | No vision/image list gains it | it appears in `noVisionModels`, never `modelInputModalities` as image | +| 3 | ox-alpha surfaces reviewed and excluded on the record | this document | +| 4 | Parity and provider tests green | narrow `bun test` on the 7 covering files | +| 5 | Types hold | `bun x tsc --noEmit` | +| 6 | Landed | CI green, PR merged, local `dev` level | + +## Loop spec + +- Archetype: spec-satisfaction repair; the verifier is the parity suite plus `rg`. +- Write scope: `src/providers/registry.ts`, the covering tests, this devlog unit. One + branch, one PR. No `main`, no force-push to `dev`. +- Escalation: if a provider's list turns out to be live-discovery-only such that seeding + is meaningless, exclude it and record that here rather than padding the diff. diff --git a/src/providers/command-code-efforts.ts b/src/providers/command-code-efforts.ts index b7d5b15d1b..b790c8779d 100644 --- a/src/providers/command-code-efforts.ts +++ b/src/providers/command-code-efforts.ts @@ -9,13 +9,6 @@ const COMMAND_CODE_MODEL_EFFORTS = { efforts: ["high", "max"], profileUrl: "https://commandcode.ai/models/deepseek-v4-flash", }, - // Ox Alpha (stealth preview, added in Command Code v1.31.0): free 1M-context - // reasoning model on every plan. The profile does not publish an effort ladder, - // so mirror the OpenRouter contract (reasoning mandatory; max/high/low). - "stealth/ox-alpha": { - efforts: ["low", "high", "max"], - profileUrl: "https://commandcode.ai/models/ox-alpha", - }, // Keys must match the EXACT upstream /provider/v1/models ids (GLM ships as // `zai-org/GLM-5.3`, not `zai-org/glm-5.3`). The table doubles as the router's // known-ids decode source (via `knownModelIdsForProvider`), so a case mismatch diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 913ca82af1..40feec0bfd 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -471,13 +471,13 @@ const OPENCODE_GO_THINKING_TOGGLE_MODELS = [ * images through the proxy's vision sidecar (src/codex/catalog/provider-fetch.ts), a claim nobody * has verified for BigModel-hosted GLM. */ -const ZHIPU_BIGMODEL_TEXT_MODELS = ["glm-4.6", "glm-4.7", "glm-4.7-flash", "glm-5", "glm-5.1", "glm-5.2", "glm-5.3"]; +const ZHIPU_BIGMODEL_TEXT_MODELS = ["glm-4.6", "glm-4.7", "glm-4.7-flash", "glm-5", "glm-5.1", "glm-5.2", "glm-5.3", "glm-5.3-flash"]; const ZHIPU_BIGMODEL_MODELS = [...ZHIPU_BIGMODEL_TEXT_MODELS, "glm-4.6v"]; const ZHIPU_BIGMODEL_INPUT_MODALITIES: Record = { ...Object.fromEntries(ZHIPU_BIGMODEL_TEXT_MODELS.map(id => [id, ["text"]])), "glm-4.6v": ["text", "image"], }; -const ZHIPU_BIGMODEL_THINKING_TOGGLE_MODELS = ["glm-4.6", "glm-4.7", "glm-5", "glm-5.1", "glm-5.2", "glm-5.3"]; +const ZHIPU_BIGMODEL_THINKING_TOGGLE_MODELS = ["glm-4.6", "glm-4.7", "glm-5", "glm-5.1", "glm-5.2", "glm-5.3", "glm-5.3-flash"]; const THINKING_BUDGET_EFFORTS = ["low", "medium", "high", "xhigh", "max"]; // Qwen3.8-Max is the first Qwen3.x model with official direct `reasoning_effort` support. // Evidence: https://qwen.ai/blog?id=qwen3.8 @@ -505,8 +505,6 @@ const DEEPSEEK_VISION_PREVIEW_MODEL = "deepseek-v4-flash-vision-exp"; * capability intersection trusts this map. */ const COMMAND_CODE_IMAGE_MODELS = [ - "stealth/ox-alpha", - "openai/ox-alpha", `deepseek/${DEEPSEEK_VISION_PREVIEW_MODEL}`, "gpt-5.6-luna", "gpt-5.6-sol", @@ -518,15 +516,6 @@ const COMMAND_CODE_IMAGE_MODELS = [ const COMMAND_CODE_MODEL_INPUT_MODALITIES: Record = Object.fromEntries(COMMAND_CODE_IMAGE_MODELS.map(id => [id, ["text", "image"]])); const OPENCODE_FREE_DEEPSEEK_MODELS = ["deepseek-v4-flash-free"]; -/* - * OpenCode Zen's free slug for the OpenRouter stealth model "Ox Alpha" - * (openrouter.ai/stealth/ox-alpha): 1,048,576-token context, multimodal - * (text+image+video upstream; Zen serves text+image), mandatory reasoning, - * free during the stealth window. Zen displays it as "Ox Alpha Free" under - * this exact id (opencode.ai/docs/zen, verified 2026-08-21). - */ -const OPENCODE_OX_ALPHA_FREE_MODEL = "x-preview-f-free"; -const OX_ALPHA_CONTEXT_WINDOW = 1_048_576; /* * Zen free models that reject `image_url` upstream (#1043, and the reproducible * half of #1024). @@ -613,7 +602,7 @@ const deepseekReasoningMapFor = (modelId: string): Record => // https://help.aliyun.com/en/model-studio/token-plan-quickstart const ALIBABA_TOKEN_PLAN_MODELS = [ "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash", - "glm-5.3", "glm-5.2", "deepseek-v4-pro", + "glm-5.3", "glm-5.3-flash", "glm-5.2", "deepseek-v4-pro", ]; const ALIBABA_TOKEN_PLAN_QWEN_MODELS = [ "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash", @@ -624,6 +613,7 @@ const ALIBABA_TOKEN_PLAN_INPUT_MODALITIES: Record = { "qwen3.7-plus": ["text", "image"], "qwen3.6-flash": ["text", "image"], "glm-5.3": ["text"], + "glm-5.3-flash": ["text", "image"], "glm-5.2": ["text"], "deepseek-v4-pro": ["text"], }; @@ -636,7 +626,7 @@ const ALIBABA_INTL_TOKEN_PLAN_MODELS = [ "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash", "deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v3.2", "kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5", - "glm-5.3", "glm-5.2", "glm-5.1", "glm-5", + "glm-5.3", "glm-5.3-flash", "glm-5.2", "glm-5.1", "glm-5", "MiniMax-M2.5", ]; const ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS = [ @@ -686,6 +676,7 @@ const VOLCENGINE_CODING_PLAN_MODELS = [ "deepseek-v4-pro", "deepseek-v4-flash", "glm-5.3", + "glm-5.3-flash", "glm-5.2", "kimi-k2.6", "minimax-m3", @@ -694,6 +685,7 @@ const VOLCENGINE_AGENT_PLAN_MODELS = [ "deepseek-v4-pro", "deepseek-v4-flash", "glm-5.3", + "glm-5.3-flash", "glm-5.2", "kimi-k2.6", "minimax-m3", @@ -712,6 +704,7 @@ const VOLCENGINE_PLAN_TEXT_ONLY_MODELS = [ "deepseek-v4-pro", "deepseek-v4-flash", "glm-5.3", + "glm-5.3-flash", "glm-5.2", "doubao-seed-2.0-pro", ]; @@ -728,6 +721,7 @@ const ALIBABA_INTL_TOKEN_PLAN_INPUT_MODALITIES: Record = { "kimi-k2.6": ["text", "image"], "kimi-k2.5": ["text", "image"], "glm-5.3": ["text"], + "glm-5.3-flash": ["text", "image"], "glm-5.2": ["text"], "glm-5.1": ["text"], "glm-5": ["text"], @@ -851,7 +845,7 @@ const NVIDIA_NIM_NO_VISION_MODELS = [ "nvidia/nemotron-3-ultra-550b-a55b", "nvidia/nemotron-mini-4b-instruct", "nvidia/nvidia-nemotron-nano-9b-v2", "openai/gpt-oss-120b", "openai/gpt-oss-20b", - "poolside/laguna-xs-2.1", "z-ai/glm-5.3", "z-ai/glm-5.2", + "poolside/laguna-xs-2.1", "z-ai/glm-5.3", "z-ai/glm-5.3-flash", "z-ai/glm-5.2", ]; const KIMI_CODING_MODEL_CONTEXT_WINDOWS: Record = Object.fromEntries( KIMI_CODING_MODELS.map(id => [id, id === "k3[1m]" ? KIMI_K3_1M_CONTEXT_WINDOW : KIMI_K3_STANDARD_CONTEXT_WINDOW]), @@ -860,7 +854,7 @@ const KIMI_CODING_MODEL_INPUT_MODALITIES = Object.fromEntries( KIMI_CODING_K3_MODELS.map(id => [id, ["text", "image"]]), ); const NEURALWATT_REASONING_HISTORY_MODELS = [ - "glm-5.3", "glm-5.3-short", + "glm-5.3", "glm-5.3-short", "glm-5.3-flash", "glm-5.2", "glm-5.2-short", "kimi-k2.6", "kimi-k2.7-code", "qwen3.5-397b", "qwen3.6-35b", @@ -941,6 +935,7 @@ const DIGITALOCEAN_CHAT_COMPLETION_MODELS = [ "nemotron-nano-12b-v2-vl", "mimo-v2.5-pro", "glm-5.3", + "glm-5.3-flash", "glm-5.2", "glm-5.1", "glm-5", @@ -949,6 +944,7 @@ const DIGITALOCEAN_CHAT_COMPLETION_MODELS = [ ] as const; const SCALEWAY_SERVERLESS_CHAT_MODELS = [ "glm-5.3", + "glm-5.3-flash", "glm-5.2", // gpt-oss-120b is intentionally omitted: Scaleway requires Responses API for tool calling, // while this preset routes Codex agent tools through Chat Completions. @@ -970,6 +966,7 @@ const UMANS_MODELS = [ "umans-kimi-k2.7", "umans-flash", "umans-glm-5.3", + "umans-glm-5.3-flash", "umans-glm-5.2", "umans-glm-5.1", "umans-qwen3.6-35b-a3b", @@ -979,12 +976,15 @@ const UMANS_GLM_REASONING_EFFORTS = ["high", "xhigh", "max"]; // 260814: Z.AI folds GLM-5.3 efforts into low/high/max, so `low` is a real tier here and // `xhigh` is not distinct from `max` (docs.z.ai/devpack/latest-model). const UMANS_GLM_53_REASONING_EFFORTS = ["low", "high", "max"]; -const UMANS_TEXT_ONLY_MODELS = ["umans-glm-5.3", "umans-glm-5.2", "umans-glm-5.1"]; +const UMANS_TEXT_ONLY_MODELS = ["umans-glm-5.3", "umans-glm-5.3-flash", "umans-glm-5.2", "umans-glm-5.1"]; const UMANS_MODEL_CONTEXT_WINDOWS: Record = { "umans-coder": 262_144, "umans-kimi-k2.7": 262_144, "umans-flash": 262_144, "umans-glm-5.3": 405_504, + // Mirrors the sibling this provider already carries. Umans has not published a + // separate window for the flash tier; asserting a different number would be a guess. + "umans-glm-5.3-flash": 405_504, "umans-glm-5.2": 405_504, "umans-glm-5.1": 202_752, "umans-qwen3.6-35b-a3b": 262_144, @@ -994,6 +994,7 @@ const UMANS_MODEL_INPUT_MODALITIES: Record = Object.fromEntrie ); const CLINE_PASS_MODELS = [ "cline-pass/glm-5.3", + "cline-pass/glm-5.3-flash", "cline-pass/glm-5.2", "cline-pass/kimi-k3", "cline-pass/kimi-k2.7-code", @@ -1009,6 +1010,7 @@ const CLINE_PASS_MODELS = [ ]; const CLINE_PASS_MODEL_CONTEXT_WINDOWS: Record = { "cline-pass/glm-5.3": 1_048_576, + "cline-pass/glm-5.3-flash": 1_048_576, "cline-pass/glm-5.2": 1_048_576, "cline-pass/kimi-k3": 1_048_576, "cline-pass/kimi-k2.7-code": 262_144, @@ -1196,11 +1198,9 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // Unknown/new live models deliberately do not advertise a reasoning picker. reasoningEfforts: [], modelReasoningEfforts: COMMAND_CODE_MODEL_REASONING_EFFORTS, - // Ox Alpha (stealth preview, changelog v1.31.0): free 1M multimodal reasoning - // model on every plan. DeepSeek vision preview id is preemptive metadata — - // it is expected to merge into deepseek-v4-flash later. + // The DeepSeek vision preview id is preemptive metadata — it is expected to + // merge into deepseek-v4-flash later. modelContextWindows: { - "stealth/ox-alpha": OX_ALPHA_CONTEXT_WINDOW, [`deepseek/${DEEPSEEK_VISION_PREVIEW_MODEL}`]: 1_048_576, }, modelInputModalities: COMMAND_CODE_MODEL_INPUT_MODALITIES, @@ -1373,6 +1373,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ "umans-kimi-k2.7": UMANS_REASONING_EFFORTS, "umans-flash": UMANS_REASONING_EFFORTS, "umans-glm-5.3": UMANS_GLM_53_REASONING_EFFORTS, + "umans-glm-5.3-flash": UMANS_GLM_53_REASONING_EFFORTS, "umans-glm-5.2": UMANS_GLM_REASONING_EFFORTS, "umans-glm-5.1": UMANS_GLM_REASONING_EFFORTS, "umans-qwen3.6-35b-a3b": UMANS_REASONING_EFFORTS, @@ -1398,21 +1399,19 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ modelWireDefaults: { "gpt-5.6-luna": "openai-responses", "muse-spark-1.2-contributor": "openai-responses" }, modelContextWindows: { "kimi-k3": KIMI_K3_STANDARD_CONTEXT_WINDOW, - // Ox Alpha (stealth 1M multimodal) and the DeepSeek vision preview are - // metadata-only here: the Go roster is discovered live, so these apply - // the moment the gateway starts serving the ids. - [OPENCODE_OX_ALPHA_FREE_MODEL]: OX_ALPHA_CONTEXT_WINDOW, + // The DeepSeek vision preview id is metadata-only here: the Go roster is + // discovered live, so it applies the moment the gateway serves the id. [DEEPSEEK_VISION_PREVIEW_MODEL]: 1_048_576, }, modelInputModalities: { "kimi-k3": ["text", "image"], - [OPENCODE_OX_ALPHA_FREE_MODEL]: ["text", "image"], // Experimental DeepSeek vision preview — expected to merge into deepseek-v4-flash later. [DEEPSEEK_VISION_PREVIEW_MODEL]: ["text", "image"], }, modelReasoningEfforts: { "gpt-5.6-luna": OPENAI_API_GPT56_REASONING_EFFORTS, "glm-5.3": ZAI_GLM_53_REASONING_EFFORTS, + "glm-5.3-flash": ZAI_GLM_53_REASONING_EFFORTS, "glm-5.2": ZAI_GLM_52_REASONING_EFFORTS, "qwen3.8-max": QWEN38_REASONING_EFFORTS, "kimi-k3": KIMI_CODING_K3_REASONING_EFFORTS, @@ -1432,6 +1431,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ }, modelSupportsReasoningSummaries: { "glm-5.3": true, + "glm-5.3-flash": true, "glm-5.2": true, "glm-5.1": true, "glm-5": true, @@ -1455,7 +1455,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ noPenaltyModels: ["kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed"], autoToolChoiceOnlyModels: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed"], // Issue #78: DeepSeek V4 thinking mode requires reasoning_content replay on tool-call turns. - preserveReasoningContentModels: ["glm-5.3", "glm-5.2", "kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed", ...DEEPSEEK_THINKING_MODELS], + preserveReasoningContentModels: ["glm-5.3", "glm-5.3-flash", "glm-5.2", "kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed", ...DEEPSEEK_THINKING_MODELS], }, { id: "neuralwatt", @@ -1471,6 +1471,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md and https://api.neuralwatt.com/v1/models. models: [ "glm-5.3", "glm-5.3-fast", "glm-5.3-short", "glm-5.3-short-fast", + "glm-5.3-flash", "glm-5.2", "glm-5.2-fast", "glm-5.2-short", "glm-5.2-short-fast", "kimi-k2.6", "kimi-k2.6-fast", "kimi-k2.7-code", @@ -1482,6 +1483,9 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ "glm-5.3-fast": [], "glm-5.3-short": ZAI_GLM_53_REASONING_EFFORTS, "glm-5.3-short-fast": [], + // No `-fast`/`-short` variants are asserted for the flash tier: those suffixes + // encode routing Neuralwatt documents per model, and this seed has no source for them. + "glm-5.3-flash": ZAI_GLM_53_REASONING_EFFORTS, "glm-5.2": ZAI_GLM_52_REASONING_EFFORTS, "glm-5.2-fast": [], "glm-5.2-short": ZAI_GLM_52_REASONING_EFFORTS, @@ -1514,16 +1518,11 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ featured: true, dashboardUrl: "https://openrouter.ai/keys", jawcodeBundle: "openrouter", - // stealth/ox-alpha: free stealth-window frontier model (launched 2026-08-20). - // /api/v1/models reports 1,048,576 context, 131,072 max output, text+image+video - // input, $0 pricing, mandatory reasoning. Single provider slug: `stealth`. - models: ["anthropic/claude-sonnet-5", "stealth/ox-alpha", ...OPENROUTER_GPT56_MODELS], + models: ["anthropic/claude-sonnet-5", ...OPENROUTER_GPT56_MODELS], modelContextWindows: { "anthropic/claude-sonnet-5": 1_000_000, - "stealth/ox-alpha": OX_ALPHA_CONTEXT_WINDOW, ...OPENROUTER_GPT56_CONTEXT_WINDOWS, }, - modelInputModalities: { "stealth/ox-alpha": ["text", "image"] }, // OpenRouter documents priority support for OpenAI endpoints, but not Anthropic. Keep the // provider unclassified and opt in only the exact OpenAI-backed slugs we ship. These facts // belong only to the canonical destination; a same-named custom gateway is unknown to us. @@ -1934,11 +1933,9 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // slash ids — so a Codex-facing slug like `commandcode/deepseek-deepseek-v4-pro` // is sent upstream verbatim and rejected with `unsupported_model`. modelReasoningEfforts: COMMAND_CODE_MODEL_REASONING_EFFORTS, - // Ox Alpha (stealth preview, Command Code changelog v1.31.0) ships with a - // 1.05M-token multimodal context; the DeepSeek vision preview id is - // preemptive for when the catalog serves it (merges into v4-flash later). + // The DeepSeek vision preview id is preemptive for when the catalog serves it + // (merges into v4-flash later). modelContextWindows: { - "stealth/ox-alpha": OX_ALPHA_CONTEXT_WINDOW, [`deepseek/${DEEPSEEK_VISION_PREVIEW_MODEL}`]: 1_048_576, }, modelInputModalities: COMMAND_CODE_MODEL_INPUT_MODALITIES, @@ -2198,8 +2195,8 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ id: "zai", label: "Z.AI — GLM Coding Plan", baseUrl: "https://api.z.ai/api/coding/paas/v4", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://z.ai/manage-apikey/apikey-list", defaultModel: "glm-5.3", note: "GLM-5.3 coding subscription", - models: ["glm-5.3", "glm-5.3[1m]", "glm-5.2", "glm-5.2[1m]", "glm-5.1", "glm-5", "glm-4.6"], - modelContextWindows: { "glm-5.3": 1_000_000, "glm-5.3[1m]": 1_000_000, "glm-5.2": 1_000_000, "glm-5.2[1m]": 1_000_000 }, + models: ["glm-5.3", "glm-5.3[1m]", "glm-5.3-flash", "glm-5.2", "glm-5.2[1m]", "glm-5.1", "glm-5", "glm-4.6"], + modelContextWindows: { "glm-5.3": 1_000_000, "glm-5.3[1m]": 1_000_000, "glm-5.3-flash": 1_000_000, "glm-5.2": 1_000_000, "glm-5.2[1m]": 1_000_000 }, // Z.AI's OpenAI path returns 400 code 1211 for bracketed model ids. modelSuffixBracketStrip: true, noVisionModels: ZAI_GLM_5X_MODELS, @@ -2279,9 +2276,9 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ authKind: "key", dashboardUrl: "https://bigmodel.cn/console/usercenter/apikeys", defaultModel: "glm-5.3", - models: ["glm-5.3", "glm-5.3[1m]", "glm-5.2", "glm-5.2[1m]", "glm-5.1", "glm-5", "glm-4.6"], + models: ["glm-5.3", "glm-5.3[1m]", "glm-5.3-flash", "glm-5.2", "glm-5.2[1m]", "glm-5.1", "glm-5", "glm-4.6"], jawcodeBundle: "zai", - modelContextWindows: { "glm-5.3": 1_000_000, "glm-5.3[1m]": 1_000_000, "glm-5.2": 1_000_000, "glm-5.2[1m]": 1_000_000 }, + modelContextWindows: { "glm-5.3": 1_000_000, "glm-5.3[1m]": 1_000_000, "glm-5.3-flash": 1_000_000, "glm-5.2": 1_000_000, "glm-5.2[1m]": 1_000_000 }, modelSuffixBracketStrip: true, noVisionModels: ZAI_GLM_5X_MODELS, modelReasoningEfforts: ZAI_GLM_5X_REASONING_EFFORTS, @@ -2425,12 +2422,13 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ modelInputModalities: ALIBABA_TOKEN_PLAN_INPUT_MODALITIES, modelContextWindows: { "qwen3.8-max": 983_616, "qwen3.7-max": 1_000_000, "qwen3.7-plus": 1_000_000, - "qwen3.6-flash": 1_000_000, "glm-5.3": 1_000_000, "glm-5.2": 1_000_000, "deepseek-v4-pro": 1_000_000, + "qwen3.6-flash": 1_000_000, "glm-5.3": 1_000_000, "glm-5.3-flash": 1_000_000, "glm-5.2": 1_000_000, "deepseek-v4-pro": 1_000_000, }, modelReasoningEfforts: { ...Object.fromEntries(ALIBABA_TOKEN_PLAN_QWEN_MODELS.map(id => [id, THINKING_BUDGET_EFFORTS])), "qwen3.8-max": QWEN38_REASONING_EFFORTS, "glm-5.3": ZAI_GLM_53_REASONING_EFFORTS, + "glm-5.3-flash": ZAI_GLM_53_REASONING_EFFORTS, "glm-5.2": ZAI_GLM_52_REASONING_EFFORTS, "deepseek-v4-pro": deepseekThinkingEffortsFor("deepseek-v4-pro"), }, @@ -2438,7 +2436,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ modelReasoningEffortMap: { "deepseek-v4-pro": deepseekReasoningMapFor("deepseek-v4-pro") }, directReasoningEffortModels: ["qwen3.8-max"], thinkingBudgetModels: ALIBABA_TOKEN_PLAN_QWEN_MODELS.filter(id => id !== "qwen3.8-max"), - preserveReasoningContentModels: ["glm-5.3", "glm-5.2", "deepseek-v4-pro", "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash"], + preserveReasoningContentModels: ["glm-5.3", "glm-5.3-flash", "glm-5.2", "deepseek-v4-pro", "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash"], noVisionModels: ["glm-5.3", "glm-5.2", "deepseek-v4-pro"], }, { @@ -2461,13 +2459,14 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ "qwen3.7-max": 1_000_000, "qwen3.7-plus": 1_000_000, "qwen3.6-plus": 1_000_000, "qwen3.6-flash": 1_000_000, "deepseek-v4-pro": 1_000_000, "deepseek-v4-flash": 1_000_000, "deepseek-v3.2": 131_072, "kimi-k2.7-code": 262_144, "kimi-k2.6": 262_144, "kimi-k2.5": 262_144, - "glm-5.3": 1_000_000, "glm-5.2": 1_000_000, "glm-5.1": 1_000_000, "glm-5": 1_000_000, + "glm-5.3": 1_000_000, "glm-5.3-flash": 1_000_000, "glm-5.2": 1_000_000, "glm-5.1": 1_000_000, "glm-5": 1_000_000, "MiniMax-M2.5": 204_800, }, modelReasoningEfforts: { ...Object.fromEntries(ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS.map(id => [id, THINKING_BUDGET_EFFORTS])), "qwen3.8-max": QWEN38_REASONING_EFFORTS, "glm-5.3": ZAI_GLM_53_REASONING_EFFORTS, + "glm-5.3-flash": ZAI_GLM_53_REASONING_EFFORTS, "glm-5.2": ZAI_GLM_52_REASONING_EFFORTS, "deepseek-v4-pro": deepseekThinkingEffortsFor("deepseek-v4-pro"), "deepseek-v4-flash": deepseekThinkingEffortsFor("deepseek-v4-flash"), @@ -2478,7 +2477,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ }, directReasoningEffortModels: ["qwen3.8-max"], thinkingBudgetModels: ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS.filter(id => id !== "qwen3.8-max"), - preserveReasoningContentModels: ["glm-5.3", "glm-5.2", "deepseek-v4-pro", "deepseek-v4-flash", "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash"], + preserveReasoningContentModels: ["glm-5.3", "glm-5.3-flash", "glm-5.2", "deepseek-v4-pro", "deepseek-v4-flash", "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash"], noVisionModels: ["deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v3.2", "glm-5.3", "glm-5.2", "glm-5.1", "glm-5", "MiniMax-M2.5"], noReasoningModels: ["kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5", "deepseek-v3.2", "glm-5.1", "glm-5", "MiniMax-M2.5"], modelDefaultReasoningEfforts: { "qwen3.8-max": "xhigh" }, @@ -2511,10 +2510,10 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ authKind: "key", dashboardUrl: "https://ollama.com/settings/keys", // Live IDs verified 2026-07-10; qwen3-coder:480b retires 2026-07-15. - models: ["glm-5.3", "glm-5.2", "deepseek-v4-pro", "qwen3-coder:480b", "gpt-oss:120b", "kimi-k2.6", "minimax-m3", "qwen3.5:397b", "gemma4:31b"], + models: ["glm-5.3", "glm-5.3-flash", "glm-5.2", "deepseek-v4-pro", "qwen3-coder:480b", "gpt-oss:120b", "kimi-k2.6", "minimax-m3", "qwen3.5:397b", "gemma4:31b"], defaultModel: "glm-5.3", noVisionModels: [ - "glm-5.3", "glm-5.2", "glm-5.1", "glm-5", "glm-4.7", + "glm-5.3", "glm-5.3-flash", "glm-5.2", "glm-5.1", "glm-5", "glm-4.7", "minimax-m2.7", "minimax-m2.5", "minimax-m2.1", "nemotron-3-ultra", "nemotron-3-super", "deepseek-v4-pro", "deepseek-v4-flash", @@ -2586,14 +2585,12 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ [...DEEPSEEK_THINKING_MODELS, ...OPENCODE_FREE_DEEPSEEK_MODELS].map(id => [id, deepseekReasoningMapFor(id)]), ), preserveReasoningContentModels: [...DEEPSEEK_THINKING_MODELS, ...OPENCODE_FREE_DEEPSEEK_MODELS], - // Same Zen gateway as opencode-free: Ox Alpha Free (1M multimodal stealth model) - // and the DeepSeek vision preview (merges into deepseek-v4-flash later). + // Same Zen gateway as opencode-free: the DeepSeek vision preview id + // (merges into deepseek-v4-flash later). modelContextWindows: { - [OPENCODE_OX_ALPHA_FREE_MODEL]: OX_ALPHA_CONTEXT_WINDOW, [DEEPSEEK_VISION_PREVIEW_MODEL]: 1_048_576, }, modelInputModalities: { - [OPENCODE_OX_ALPHA_FREE_MODEL]: ["text", "image"], [DEEPSEEK_VISION_PREVIEW_MODEL]: ["text", "image"], }, noVisionModels: [...OPENCODE_ZEN_TEXT_ONLY_MODELS, ...DEEPSEEK_THINKING_MODELS], @@ -2626,16 +2623,12 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ modelReasoningEfforts: Object.fromEntries(OPENCODE_FREE_DEEPSEEK_MODELS.map(id => [id, deepseekThinkingEffortsFor(id)])), modelReasoningEffortMap: Object.fromEntries(OPENCODE_FREE_DEEPSEEK_MODELS.map(id => [id, deepseekReasoningMapFor(id)])), preserveReasoningContentModels: OPENCODE_FREE_DEEPSEEK_MODELS, - // Ox Alpha Free (`x-preview-f-free`): the OpenRouter stealth model on Zen's - // free tier — 1,048,576 context, text+image input. Deliberately NOT in the - // text-only list below. The DeepSeek vision preview id is preemptive - // metadata for when Zen starts serving it (merges into v4-flash later). + // The DeepSeek vision preview id is preemptive metadata for when Zen starts + // serving it (merges into v4-flash later). modelContextWindows: { - [OPENCODE_OX_ALPHA_FREE_MODEL]: OX_ALPHA_CONTEXT_WINDOW, [DEEPSEEK_VISION_PREVIEW_MODEL]: 1_048_576, }, modelInputModalities: { - [OPENCODE_OX_ALPHA_FREE_MODEL]: ["text", "image"], [DEEPSEEK_VISION_PREVIEW_MODEL]: ["text", "image"], }, // Same Zen roster behind the same base URL, so it carries the same measured @@ -2727,6 +2720,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b", "@cf/moonshotai/kimi-k2.7-code", "@cf/zai-org/glm-5.3", + "@cf/zai-org/glm-5.3-flash", "@cf/zai-org/glm-5.2", "@cf/mistralai/mistral-small-3.1-24b-instruct", ], diff --git a/tests/alibaba-intl-token-plan.test.ts b/tests/alibaba-intl-token-plan.test.ts index 459ccfd092..c76a9c364b 100644 --- a/tests/alibaba-intl-token-plan.test.ts +++ b/tests/alibaba-intl-token-plan.test.ts @@ -32,9 +32,10 @@ describe("alibaba-token-plan-intl registry entry", () => { expect(entry!.models).toContain("kimi-k2.7-code"); expect(entry!.models).toContain("glm-5.2"); expect(entry!.models).toContain("glm-5.3"); + expect(entry!.models).toContain("glm-5.3-flash"); expect(entry!.models).toContain("MiniMax-M2.5"); expect(entry!.models).toContain("qwen3.8-max"); - expect(entry!.models!.length).toBe(16); + expect(entry!.models!.length).toBe(17); }); test("MiniMax case-insensitive normalization is set", () => { diff --git a/tests/cline-pass-provider.test.ts b/tests/cline-pass-provider.test.ts index 3bd7d7b827..94072bc60a 100644 --- a/tests/cline-pass-provider.test.ts +++ b/tests/cline-pass-provider.test.ts @@ -9,6 +9,7 @@ import type { OcxConfig, OcxParsedRequest } from "../src/types"; const OFFICIAL_CLINE_PASS_MODELS = [ "cline-pass/glm-5.3", + "cline-pass/glm-5.3-flash", "cline-pass/glm-5.2", "cline-pass/kimi-k3", "cline-pass/kimi-k2.7-code", @@ -71,6 +72,7 @@ describe("ClinePass provider", () => { expect(entry?.modelMaxInputTokens).toBeUndefined(); expect(entry?.noVisionModels).toEqual([ "cline-pass/glm-5.3", + "cline-pass/glm-5.3-flash", "cline-pass/glm-5.2", "cline-pass/deepseek-v4-pro", "cline-pass/deepseek-v4-flash", diff --git a/tests/command-code-provider.test.ts b/tests/command-code-provider.test.ts index b342b56da5..9c5e02ed26 100644 --- a/tests/command-code-provider.test.ts +++ b/tests/command-code-provider.test.ts @@ -87,8 +87,6 @@ describe("Command Code provider", () => { const oauth = PROVIDER_REGISTRY.find(row => row.id === "command-code"); const apiKey = PROVIDER_REGISTRY.find(row => row.id === "commandcode"); const verifiedImageModels = [ - "stealth/ox-alpha", - "openai/ox-alpha", "deepseek/deepseek-v4-flash-vision-exp", "gpt-5.6-luna", "gpt-5.6-sol", diff --git a/tests/provider-model-discovery-contract.test.ts b/tests/provider-model-discovery-contract.test.ts index c49d4062dd..b8b47adf9e 100644 --- a/tests/provider-model-discovery-contract.test.ts +++ b/tests/provider-model-discovery-contract.test.ts @@ -442,6 +442,7 @@ describe("registry-owned provider model discovery", () => { "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b", "@cf/moonshotai/kimi-k2.7-code", "@cf/zai-org/glm-5.3", + "@cf/zai-org/glm-5.3-flash", "@cf/zai-org/glm-5.2", "@cf/mistralai/mistral-small-3.1-24b-instruct", ]); diff --git a/tests/provider-registry-parity.test.ts b/tests/provider-registry-parity.test.ts index e421907058..1f155d76df 100644 --- a/tests/provider-registry-parity.test.ts +++ b/tests/provider-registry-parity.test.ts @@ -307,7 +307,7 @@ describe("provider registry parity", () => { liveModels: false, models: [ "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash", - "glm-5.3", "glm-5.2", "deepseek-v4-pro", + "glm-5.3", "glm-5.3-flash", "glm-5.2", "deepseek-v4-pro", ], modelInputModalities: { "qwen3.8-max": ["text", "image"], @@ -340,6 +340,7 @@ describe("provider registry parity", () => { const neuralwatt = PROVIDER_REGISTRY.find(entry => entry.id === "neuralwatt"); expect(neuralwatt?.models).toEqual([ "glm-5.3", "glm-5.3-fast", "glm-5.3-short", "glm-5.3-short-fast", + "glm-5.3-flash", "glm-5.2", "glm-5.2-fast", "glm-5.2-short", "glm-5.2-short-fast", "kimi-k2.6", "kimi-k2.6-fast", "kimi-k2.7-code", "qwen3.5-397b", "qwen3.5-397b-fast", "qwen3.6-35b", "qwen3.6-35b-fast", @@ -367,7 +368,7 @@ describe("provider registry parity", () => { const optedInProviders = PROVIDER_REGISTRY .filter(entry => entry.modelSuffixBracketStrip) .map(entry => entry.id); - expect(zai?.modelContextWindows).toEqual({ "glm-5.3": 1_000_000, "glm-5.3[1m]": 1_000_000, "glm-5.2": 1_000_000, "glm-5.2[1m]": 1_000_000 }); + expect(zai?.modelContextWindows).toEqual({ "glm-5.3": 1_000_000, "glm-5.3[1m]": 1_000_000, "glm-5.3-flash": 1_000_000, "glm-5.2": 1_000_000, "glm-5.2[1m]": 1_000_000 }); expect(zai?.modelDefaultReasoningEfforts).toEqual({ "glm-5.3": "max", "glm-5.3[1m]": "max" }); expect(zai?.modelMaxOutputTokens).toEqual({ "glm-5.3": 131_072, "glm-5.3[1m]": 131_072 }); expect(providerConfigSeed(zai!).modelSuffixBracketStrip).toBe(true); @@ -582,7 +583,7 @@ describe("provider registry parity", () => { const ollamaCloud = PROVIDER_REGISTRY.find(entry => entry.id === "ollama-cloud"); expect(ollamaCloud?.models).toEqual([ - "glm-5.3", "glm-5.2", "deepseek-v4-pro", "qwen3-coder:480b", "gpt-oss:120b", + "glm-5.3", "glm-5.3-flash", "glm-5.2", "deepseek-v4-pro", "qwen3-coder:480b", "gpt-oss:120b", "kimi-k2.6", "minimax-m3", "qwen3.5:397b", "gemma4:31b", ]); expect(ollamaCloud?.models).not.toContain("qwen3-coder"); diff --git a/tests/volcengine-providers.test.ts b/tests/volcengine-providers.test.ts index bc1ee444b9..2dba569a24 100644 --- a/tests/volcengine-providers.test.ts +++ b/tests/volcengine-providers.test.ts @@ -60,6 +60,7 @@ describe("Volcengine Ark providers", () => { "deepseek-v4-pro", "deepseek-v4-flash", "glm-5.3", + "glm-5.3-flash", "glm-5.2", "kimi-k2.6", "minimax-m3", @@ -93,6 +94,7 @@ describe("Volcengine Ark providers", () => { "deepseek-v4-pro", "deepseek-v4-flash", "glm-5.3", + "glm-5.3-flash", "glm-5.2", "kimi-k2.6", "minimax-m3",