From ca4a90b5c559d3e6ff9ad60a9c4b500874343205 Mon Sep 17 00:00:00 2001 From: olddonkey Date: Wed, 12 Aug 2026 23:28:17 -0700 Subject: [PATCH 1/3] fix(xai): advertise grok-4.6 xhigh instead of clamping it to high The Grok 4.6 seed still used the 4.5 low/medium/high ladder, so Codex xhigh requests never left the proxy. Keep 4.5 unchanged and send the documented xhigh rung on 4.6. Closes #1592 --- src/providers/registry.ts | 9 +++--- .../catalog-vision-sidecar-modalities.test.ts | 1 + tests/effort-policy.test.ts | 2 ++ tests/provider-registry-parity.test.ts | 18 ++++++++++++ tests/reasoning-effort.test.ts | 29 +++++++++++++++++++ 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 83beadd941..4b75c4c76e 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -950,8 +950,8 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // devlog/model_update/260709_model_refresh/001_xai_lineup.md. // grok-4.20-multi-agent-0309 is intentionally absent: the OAuth chat-completions // transport returns 400 ("Multi Agent requests are not allowed on chat completions"). - // 260813: grok-4.6 added per the new docs.x.ai/developers/grok-4-6 page; specs mirrored - // from grok-4.5 until the official capability/pricing tables settle. + // 260813: grok-4.6 added per docs.x.ai/developers/grok-4-6. Context/vision still match + // grok-4.5; the reasoning ladder does not — 4.6 adds the documented xhigh rung. models: ["grok-4.6", "grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning", "grok-4.20-0309-non-reasoning", "grok-build-0.1", "grok-composer-2.5-fast"], defaultModel: "grok-4.5", // Vision lineup per docs.x.ai model-capabilities/images/understanding: the grok-4.x chat @@ -973,8 +973,9 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // (docs.x.ai prompt-caching/multi-turn, verified 2026-07-13 — devlog/_plan/260713_grok_caching). // Models that never emit reasoning simply have no thinking parts to replay (no-op). preserveReasoningContentModels: ["grok-4.6", "grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning"], - // grok-4.5 reasoning is always-on with low/medium/high control (no off tier upstream). - modelReasoningEfforts: { "grok-4.6": ["low", "medium", "high"], "grok-4.5": ["low", "medium", "high"] }, + // grok-4.5 reasoning is always-on with low/medium/high (no off tier, no xhigh). + // grok-4.6 adds xhigh per docs.x.ai/docs/guides/reasoning (default remains high). + modelReasoningEfforts: { "grok-4.6": ["low", "medium", "high", "xhigh"], "grok-4.5": ["low", "medium", "high"] }, modelContextWindows: { "grok-4.6": 500_000, "grok-4.5": 500_000, diff --git a/tests/catalog-vision-sidecar-modalities.test.ts b/tests/catalog-vision-sidecar-modalities.test.ts index 27de9d504b..c49347025e 100644 --- a/tests/catalog-vision-sidecar-modalities.test.ts +++ b/tests/catalog-vision-sidecar-modalities.test.ts @@ -156,6 +156,7 @@ describe("vision-capable provider models feed combo modalities", () => { test("xAI grok chat models declare image input in the registry", () => { const xai = PROVIDER_REGISTRY.find(entry => entry.id === "xai"); for (const model of [ + "grok-4.6", "grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning", diff --git a/tests/effort-policy.test.ts b/tests/effort-policy.test.ts index fbad670ea8..1c26b40dd8 100644 --- a/tests/effort-policy.test.ts +++ b/tests/effort-policy.test.ts @@ -219,6 +219,8 @@ describe("supportedLadderFor (real routeModel routes)", () => { } as Partial); const route = routeModel(config, "xai/grok-4.5"); expect(supportedLadderFor(route)).toEqual(["low", "medium", "high"]); + const grok46 = routeModel(config, "xai/grok-4.6"); + expect(supportedLadderFor(grok46)).toEqual(["low", "medium", "high", "xhigh"]); const noReasoning = routeModel(config, "xai/grok-composer-2.5-fast"); expect(supportedLadderFor(noReasoning)).toEqual([]); }); diff --git a/tests/provider-registry-parity.test.ts b/tests/provider-registry-parity.test.ts index 653b23fee2..04e2261dbb 100644 --- a/tests/provider-registry-parity.test.ts +++ b/tests/provider-registry-parity.test.ts @@ -670,8 +670,11 @@ describe("provider registry parity", () => { } expect(OAUTH_PROVIDERS.xai.providerConfig.defaultModel).toBe("grok-4.5"); expect(OAUTH_PROVIDERS.xai.providerConfig.liveModels).toBe(true); + expect(OAUTH_PROVIDERS.xai.providerConfig.models).toContain("grok-4.6"); expect(OAUTH_PROVIDERS.xai.providerConfig.models).toContain("grok-4.5"); + expect(OAUTH_PROVIDERS.xai.providerConfig.modelContextWindows?.["grok-4.6"]).toBe(500_000); expect(OAUTH_PROVIDERS.xai.providerConfig.modelContextWindows?.["grok-4.5"]).toBe(500_000); + expect(OAUTH_PROVIDERS.xai.providerConfig.modelReasoningEfforts?.["grok-4.6"]).toEqual(["low", "medium", "high", "xhigh"]); expect(OAUTH_PROVIDERS.xai.providerConfig.modelReasoningEfforts?.["grok-4.5"]).toEqual(["low", "medium", "high"]); expect(OAUTH_PROVIDERS.xai.providerConfig.noVisionModels).toContain("grok-build-0.1"); const antigravityRegistry = PROVIDER_REGISTRY.find(entry => entry.id === "google-antigravity"); @@ -847,6 +850,21 @@ describe("provider registry parity", () => { .toEqual(["low", "medium", "high", "max", "ultra"]); }); + test("grok-4.6 advertises the documented xhigh rung from the xai registry seed", () => { + const xai = PROVIDER_REGISTRY.find(entry => entry.id === "xai"); + const seed = providerConfigSeed(xai!); + const model = applyProviderConfigHints("xai", seed, { id: "grok-4.6", provider: "xai" }); + expect(model.contextWindow).toBe(500_000); + expect(model.reasoningEfforts).toEqual(["low", "medium", "high", "xhigh"]); + + const entries = buildCatalogEntries(nativeTemplate() as never, [], [model]); + const entry = entries.find(e => e.slug === "xai/grok-4.6"); + expect(entry).toBeTruthy(); + expect(entry?.context_window).toBe(500_000); + expect((entry?.supported_reasoning_levels as { effort: string }[]).map(l => l.effort)) + .toEqual(["low", "medium", "high", "xhigh", "max", "ultra"]); + }); + // The id-list assertion above only proves the preset exists. Pin the contract a user actually // depends on: which endpoint the key is sent to, which adapter parses the stream, and that the // vendor-namespaced seed models survive into a real catalog entry. diff --git a/tests/reasoning-effort.test.ts b/tests/reasoning-effort.test.ts index 0cfe325090..9672afc650 100644 --- a/tests/reasoning-effort.test.ts +++ b/tests/reasoning-effort.test.ts @@ -99,6 +99,35 @@ describe("provider-specific reasoning effort mapping", () => { }); }); + test("xAI grok-4.6 forwards xhigh while grok-4.5 still clamps it to high", () => { + const config: OcxConfig = { + port: 10100, + defaultProvider: "xai", + providers: { + xai: { + adapter: "openai-chat", + baseUrl: "https://api.x.ai/v1", + apiKey: "key", + }, + }, + }; + const grok46 = routeModel(config, "xai/grok-4.6"); + const grok45 = routeModel(config, "xai/grok-4.5"); + + expect(configuredReasoningEfforts(grok46.provider, grok46.modelId)).toEqual(["low", "medium", "high", "xhigh"]); + expect(configuredReasoningEfforts(grok45.provider, grok45.modelId)).toEqual(["low", "medium", "high"]); + + const grok46Xhigh = buildChatRequest(grok46.provider, grok46.modelId, { reasoning: "xhigh" }); + const grok46Max = buildChatRequest(grok46.provider, grok46.modelId, { reasoning: "max" }); + const grok45Xhigh = buildChatRequest(grok45.provider, grok45.modelId, { reasoning: "xhigh" }); + + expect(JSON.parse(grok46Xhigh.body).reasoning_effort).toBe("xhigh"); + expect(JSON.parse(grok46Max.body).reasoning_effort).toBe("xhigh"); + expect(JSON.parse(grok45Xhigh.body).reasoning_effort).toBe("high"); + expect(mapReasoningEffort(grok46.provider, grok46.modelId, "xhigh")).toBe("xhigh"); + expect(mapReasoningEffort(grok45.provider, grok45.modelId, "xhigh")).toBe("high"); + }); + test("Neuralwatt GLM-5.2 sends direct max and preserves reasoning history", () => { const provider: OcxProviderConfig = { adapter: "openai-chat", From 31185fe8f7d3092b8a17934782e52b7f21320df3 Mon Sep 17 00:00:00 2001 From: olddonkey Date: Wed, 12 Aug 2026 23:41:50 -0700 Subject: [PATCH 2/3] fix(xai): preserve grok-4.6 defaults and stale configs --- src/providers/registry.ts | 4 ++++ tests/provider-registry-parity.test.ts | 3 +++ tests/reasoning-effort.test.ts | 26 ++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 4b75c4c76e..8edb438b53 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -976,6 +976,10 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // grok-4.5 reasoning is always-on with low/medium/high (no off tier, no xhigh). // grok-4.6 adds xhigh per docs.x.ai/docs/guides/reasoning (default remains high). modelReasoningEfforts: { "grok-4.6": ["low", "medium", "high", "xhigh"], "grok-4.5": ["low", "medium", "high"] }, + modelDefaultReasoningEfforts: { "grok-4.6": "high" }, + // Codex's synthetic max rung resolves to xAI's real top rung. The mapped xhigh value also + // lets a non-empty pre-4.6 API-key ladder self-heal without changing grok-4.5. + modelReasoningEffortMap: { "grok-4.6": { max: "xhigh" } }, modelContextWindows: { "grok-4.6": 500_000, "grok-4.5": 500_000, diff --git a/tests/provider-registry-parity.test.ts b/tests/provider-registry-parity.test.ts index 04e2261dbb..5949bbe30b 100644 --- a/tests/provider-registry-parity.test.ts +++ b/tests/provider-registry-parity.test.ts @@ -676,6 +676,8 @@ describe("provider registry parity", () => { expect(OAUTH_PROVIDERS.xai.providerConfig.modelContextWindows?.["grok-4.5"]).toBe(500_000); expect(OAUTH_PROVIDERS.xai.providerConfig.modelReasoningEfforts?.["grok-4.6"]).toEqual(["low", "medium", "high", "xhigh"]); expect(OAUTH_PROVIDERS.xai.providerConfig.modelReasoningEfforts?.["grok-4.5"]).toEqual(["low", "medium", "high"]); + expect(OAUTH_PROVIDERS.xai.providerConfig.modelDefaultReasoningEfforts).toEqual({ "grok-4.6": "high" }); + expect(OAUTH_PROVIDERS.xai.providerConfig.modelReasoningEffortMap?.["grok-4.6"]).toEqual({ max: "xhigh" }); expect(OAUTH_PROVIDERS.xai.providerConfig.noVisionModels).toContain("grok-build-0.1"); const antigravityRegistry = PROVIDER_REGISTRY.find(entry => entry.id === "google-antigravity"); expect(antigravityRegistry?.liveModels).toBe(true); @@ -863,6 +865,7 @@ describe("provider registry parity", () => { expect(entry?.context_window).toBe(500_000); expect((entry?.supported_reasoning_levels as { effort: string }[]).map(l => l.effort)) .toEqual(["low", "medium", "high", "xhigh", "max", "ultra"]); + expect(entry?.default_reasoning_level).toBe("high"); }); // The id-list assertion above only proves the preset exists. Pin the contract a user actually diff --git a/tests/reasoning-effort.test.ts b/tests/reasoning-effort.test.ts index 9672afc650..981ee432b7 100644 --- a/tests/reasoning-effort.test.ts +++ b/tests/reasoning-effort.test.ts @@ -128,6 +128,32 @@ describe("provider-specific reasoning effort mapping", () => { expect(mapReasoningEffort(grok45.provider, grok45.modelId, "xhigh")).toBe("high"); }); + test("xAI grok-4.6 heals an old persisted API-key ladder without changing grok-4.5", () => { + const config: OcxConfig = { + port: 10100, + defaultProvider: "xai", + providers: { + xai: { + adapter: "openai-chat", + baseUrl: "https://api.x.ai/v1", + authMode: "key", + apiKey: "key", + modelReasoningEfforts: { + "grok-4.6": ["low", "medium", "high"], + "grok-4.5": ["low", "medium", "high"], + }, + }, + }, + }; + const grok46 = routeModel(config, "xai/grok-4.6"); + const grok45 = routeModel(config, "xai/grok-4.5"); + + expect(configuredReasoningEfforts(grok46.provider, grok46.modelId)).toEqual(["low", "medium", "high", "xhigh"]); + expect(mapReasoningEffort(grok46.provider, grok46.modelId, "xhigh")).toBe("xhigh"); + expect(configuredReasoningEfforts(grok45.provider, grok45.modelId)).toEqual(["low", "medium", "high"]); + expect(mapReasoningEffort(grok45.provider, grok45.modelId, "xhigh")).toBe("high"); + }); + test("Neuralwatt GLM-5.2 sends direct max and preserves reasoning history", () => { const provider: OcxProviderConfig = { adapter: "openai-chat", From f813db1090c4fb5af785711ad1ad94156ef289d2 Mon Sep 17 00:00:00 2001 From: olddonkey Date: Thu, 13 Aug 2026 01:14:46 -0700 Subject: [PATCH 3/3] fix(xai): preserve reasoning overrides --- .../content/docs/guides/codex-app-models.md | 2 +- .../docs/ko/guides/codex-app-models.md | 2 +- .../docs/ru/guides/codex-app-models.md | 2 +- .../docs/zh-cn/guides/codex-app-models.md | 2 +- .../docs/zh-tw/guides/codex-app-models.md | 2 +- src/providers/registry.ts | 6 +-- tests/oauth-provider-reconcile.test.ts | 37 +++++++++++++++++++ tests/provider-registry-parity.test.ts | 2 +- tests/reasoning-effort.test.ts | 8 ++-- 9 files changed, 50 insertions(+), 13 deletions(-) diff --git a/docs-site/src/content/docs/guides/codex-app-models.md b/docs-site/src/content/docs/guides/codex-app-models.md index 70ea33de92..eb98b134ab 100644 --- a/docs-site/src/content/docs/guides/codex-app-models.md +++ b/docs-site/src/content/docs/guides/codex-app-models.md @@ -105,7 +105,7 @@ metadata instead of an older-template approximation. | OpenAI (API key) | Exactly eight namespaced rows: `gpt-5.5`, `gpt-5.6`, Sol/Terra/Luna, and the three `*-pro` virtual ids (1,050,000 context; 922,000 max input for all eight) | | OpenRouter | `openrouter/openai/gpt-5.6-sol`, `openrouter/openai/gpt-5.6-terra`, `openrouter/openai/gpt-5.6-luna` (1,050,000) | | Cursor | Static fallback includes `cursor/gpt-5.6-sol`, `cursor/gpt-5.6-terra`, and `cursor/gpt-5.6-luna` (1,000,000), plus `cursor/grok-4.5` and `cursor/grok-4.5-fast` (500,000); live account discovery decides which remain visible. | -| xAI | Live discovery is authoritative; the fallback catalog defaults to `xai/grok-4.5` with a 500,000-token window and `low` / `medium` / `high` reasoning controls. | +| xAI | Live discovery is authoritative. The fallback catalog includes `xai/grok-4.6` and defaults to `xai/grok-4.5`; both have 500,000-token windows. Grok 4.6 exposes `low` / `medium` / `high` / `xhigh` (upstream default: `high`), while Grok 4.5 stops at `high`. | The pinned GPT-5.6 entries preserve the exact upstream ladder. Sol and Terra expose `low` through `ultra`; Luna stops at `max`. Sol defaults to `low`, while Terra and Luna default to `medium`. diff --git a/docs-site/src/content/docs/ko/guides/codex-app-models.md b/docs-site/src/content/docs/ko/guides/codex-app-models.md index b6f31f1b5f..31c630742a 100644 --- a/docs-site/src/content/docs/ko/guides/codex-app-models.md +++ b/docs-site/src/content/docs/ko/guides/codex-app-models.md @@ -84,7 +84,7 @@ GPT-5.6에만 사용합니다. 오래된 템플릿으로 근사하지 않고 모 | OpenAI(API key) | 정확히 여덟 개의 네임스페이스 행: `gpt-5.5`, `gpt-5.6`, Sol/Terra/Luna, 그리고 세 개의 `*-pro` 가상 id (모두 컨텍스트 1,050,000; 최대 입력 922,000) | | OpenRouter | `openrouter/openai/gpt-5.6-sol`, `openrouter/openai/gpt-5.6-terra`, `openrouter/openai/gpt-5.6-luna` (1,050,000) | | Cursor | 정적 폴백에는 `cursor/gpt-5.6-sol`, `cursor/gpt-5.6-terra`, `cursor/gpt-5.6-luna` (1,000,000)와 `cursor/grok-4.5`, `cursor/grok-4.5-fast` (500,000)가 들어갑니다. 실시간 계정 탐색이 어떤 항목을 계속 보일지 정합니다. | -| xAI | 실시간 탐색이 기준입니다. 폴백 카탈로그의 기본값은 `xai/grok-4.5`이고, 컨텍스트 500,000과 `low` / `medium` / `high` 추론 제어를 제공합니다. | +| xAI | 실시간 탐색이 기준입니다. 폴백 카탈로그에는 `xai/grok-4.6`이 포함되며 기본값은 `xai/grok-4.5`입니다. 두 모델 모두 컨텍스트 창은 500,000입니다. Grok 4.6은 `low` / `medium` / `high` / `xhigh`(업스트림 기본값: `high`)를 제공하고, Grok 4.5는 `high`까지만 제공합니다. | 고정된 GPT-5.6 항목은 업스트림 ladder를 그대로 보존합니다. Sol과 Terra는 `low`부터 `ultra`까지 노출하고, Luna는 `max`에서 멈춥니다. Sol의 기본값은 `low`이고, Terra와 Luna의 기본값은 `medium`입니다. `ultra`는 diff --git a/docs-site/src/content/docs/ru/guides/codex-app-models.md b/docs-site/src/content/docs/ru/guides/codex-app-models.md index 425e71464c..e7fa59eb0f 100644 --- a/docs-site/src/content/docs/ru/guides/codex-app-models.md +++ b/docs-site/src/content/docs/ru/guides/codex-app-models.md @@ -90,7 +90,7 @@ per-model identity и метаданные вместо приближения | OpenAI (API key) | Ровно восемь namespaced-строк: `gpt-5.5`, `gpt-5.6`, Sol/Terra/Luna и три виртуальных id `*-pro` (контекст 1,050,000; максимум входа 922,000 у всех восьми) | | OpenRouter | `openrouter/openai/gpt-5.6-sol`, `openrouter/openai/gpt-5.6-terra`, `openrouter/openai/gpt-5.6-luna` (1,050,000) | | Cursor | Статический fallback включает `cursor/gpt-5.6-sol`, `cursor/gpt-5.6-terra` и `cursor/gpt-5.6-luna` (1,000,000), а также `cursor/grok-4.5` и `cursor/grok-4.5-fast` (500,000); какие из них останутся видимыми, решает live-discovery аккаунта. | -| xAI | Live-discovery авторитетно; fallback-каталог по умолчанию содержит `xai/grok-4.5` с окном 500,000 токенов и reasoning-control `low` / `medium` / `high`. | +| xAI | Live-discovery авторитетно. Fallback-каталог включает `xai/grok-4.6`, а моделью по умолчанию остаётся `xai/grok-4.5`; у обеих окно 500,000 токенов. Grok 4.6 поддерживает `low` / `medium` / `high` / `xhigh` (upstream-default: `high`), а Grok 4.5 — только до `high`. | Закреплённые записи GPT-5.6 сохраняют точную upstream-лестницу. Sol и Terra дают диапазон от `low` до `ultra`; у Luna верхняя ступень — `max`. По умолчанию у Sol стоит `low`, а у Terra и diff --git a/docs-site/src/content/docs/zh-cn/guides/codex-app-models.md b/docs-site/src/content/docs/zh-cn/guides/codex-app-models.md index c5773baae9..61dd5abb51 100644 --- a/docs-site/src/content/docs/zh-cn/guides/codex-app-models.md +++ b/docs-site/src/content/docs/zh-cn/guides/codex-app-models.md @@ -70,7 +70,7 @@ visibility = "list" | OpenAI(API key) | 恰好八个命名空间行:`gpt-5.5`、`gpt-5.6`、Sol/Terra/Luna,以及三个 `*-pro` 虚拟 id(八个条目均为 1,050,000 context / 922,000 max input) | | OpenRouter | `openrouter/openai/gpt-5.6-sol`、`openrouter/openai/gpt-5.6-terra`、`openrouter/openai/gpt-5.6-luna`(1,050,000) | | Cursor | 静态回退包含 `cursor/gpt-5.6-sol`、`cursor/gpt-5.6-terra`、`cursor/gpt-5.6-luna`(1,000,000),以及 `cursor/grok-4.5` 和 `cursor/grok-4.5-fast`(500,000);实时账户发现会决定最终哪些条目仍然可见。 | -| xAI | 实时发现具有权威性;回退目录默认使用 `xai/grok-4.5`,上下文窗口为 500,000,并提供 `low` / `medium` / `high` reasoning 控制。 | +| xAI | 实时发现具有权威性。回退目录包含 `xai/grok-4.6`,默认模型仍为 `xai/grok-4.5`;两者的上下文窗口均为 500,000。Grok 4.6 提供 `low` / `medium` / `high` / `xhigh`(上游默认值为 `high`),Grok 4.5 最高为 `high`。 | 固定的 GPT-5.6 条目保留了精确的上游阶梯。Sol 和 Terra 暴露从 `low` 到 `ultra` 的档位;Luna 只到 `max`。Sol 默认是 `low`,Terra 和 Luna 默认是 `medium`。`ultra` 是面向客户端的最大 reasoning 加主动委派选项,在后端会以 `max` 传入。选择器里的一个条目只表示目录已经准备好:关联的账户或 API key 仍然必须有权使用该模型。 diff --git a/docs-site/src/content/docs/zh-tw/guides/codex-app-models.md b/docs-site/src/content/docs/zh-tw/guides/codex-app-models.md index 0bc0e5e4d8..3630f64012 100644 --- a/docs-site/src/content/docs/zh-tw/guides/codex-app-models.md +++ b/docs-site/src/content/docs/zh-tw/guides/codex-app-models.md @@ -92,7 +92,7 @@ GPT-5.6,以便提供每個模型真實的身份和後設資料,而不是套 | OpenAI(API key) | 恰好八個帶名稱空間的列:`gpt-5.5`、`gpt-5.6`、Sol/Terra/Luna 與三個 `*-pro` 虛擬 id(全部八個都是 1,050,000 context;922,000 max input) | | OpenRouter | `openrouter/openai/gpt-5.6-sol`、`openrouter/openai/gpt-5.6-terra`、`openrouter/openai/gpt-5.6-luna`(1,050,000) | | Cursor | 靜態回退目錄包含 `cursor/gpt-5.6-sol`、`cursor/gpt-5.6-terra`、`cursor/gpt-5.6-luna`(1,000,000),以及 `cursor/grok-4.5`、`cursor/grok-4.5-fast`(500,000);帳號的即時發現結果決定最終顯示哪些模型。 | -| xAI | 以即時發現結果為準;回退目錄預設使用 `xai/grok-4.5`,視窗為 500,000 token,並提供 `low` / `medium` / `high` reasoning 控制。 | +| xAI | 以即時發現結果為準。回退目錄包含 `xai/grok-4.6`,預設模型仍為 `xai/grok-4.5`;兩者的 context window 均為 500,000。Grok 4.6 提供 `low` / `medium` / `high` / `xhigh`(上游預設值為 `high`),Grok 4.5 最高為 `high`。 | 固定的 GPT-5.6 條目會保留精確的上游 reasoning 階梯。Sol 和 Terra 從 `low` 到 `ultra`,Luna 最高到 `max`。Sol 預設使用 `low`,Terra 和 Luna 預設使用 `medium`。`ultra` 是用戶端側的 diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 8edb438b53..0d8a377ca7 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -974,12 +974,10 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // Models that never emit reasoning simply have no thinking parts to replay (no-op). preserveReasoningContentModels: ["grok-4.6", "grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning"], // grok-4.5 reasoning is always-on with low/medium/high (no off tier, no xhigh). - // grok-4.6 adds xhigh per docs.x.ai/docs/guides/reasoning (default remains high). + // grok-4.6 adds xhigh per docs.x.ai/developers/model-capabilities/text/reasoning; + // xAI documents high as the upstream default. modelReasoningEfforts: { "grok-4.6": ["low", "medium", "high", "xhigh"], "grok-4.5": ["low", "medium", "high"] }, modelDefaultReasoningEfforts: { "grok-4.6": "high" }, - // Codex's synthetic max rung resolves to xAI's real top rung. The mapped xhigh value also - // lets a non-empty pre-4.6 API-key ladder self-heal without changing grok-4.5. - modelReasoningEffortMap: { "grok-4.6": { max: "xhigh" } }, modelContextWindows: { "grok-4.6": 500_000, "grok-4.5": 500_000, diff --git a/tests/oauth-provider-reconcile.test.ts b/tests/oauth-provider-reconcile.test.ts index d00f8de1ae..6cfebb8509 100644 --- a/tests/oauth-provider-reconcile.test.ts +++ b/tests/oauth-provider-reconcile.test.ts @@ -5,6 +5,7 @@ import { join } from "node:path"; import { loadConfig } from "../src/config"; import { OAUTH_PROVIDERS, reconcileOAuthProviders, upsertOAuthProvider } from "../src/oauth"; import { getCredential, saveCredential } from "../src/oauth/store"; +import { routeModel } from "../src/router"; import type { OcxConfig } from "../src/types"; const originalHome = process.env.OPENCODEX_HOME; @@ -189,4 +190,40 @@ describe("OAuth provider reconciliation", () => { reconcileOAuthProviders(config); expect(config.providers.kimi.requiresReasoningPlaceholderModels).toEqual([]); }); + + test("refreshes Grok 4.6 levels while runtime fills the default without overwriting user intent", () => { + const home = mkdtempSync(join(tmpdir(), "ocx-grok-46-reconcile-")); + homes.push(home); + process.env.OPENCODEX_HOME = home; + const staleXai = structuredClone(OAUTH_PROVIDERS.xai.providerConfig); + staleXai.modelReasoningEfforts = { + "grok-4.6": ["low", "medium", "high"], + "grok-4.5": ["low", "medium", "high"], + }; + delete staleXai.modelDefaultReasoningEfforts; + const config = { + port: 10100, + defaultProvider: "xai", + providers: { + xai: { + ...staleXai, + note: "user-owned-note", + }, + }, + } satisfies OcxConfig; + + expect(reconcileOAuthProviders(config)).toBe(true); + expect(config.providers.xai.modelReasoningEfforts?.["grok-4.6"]) + .toEqual(["low", "medium", "high", "xhigh"]); + expect(config.providers.xai.modelDefaultReasoningEfforts).toBeUndefined(); + expect(routeModel(config, "xai/grok-4.6").provider.modelDefaultReasoningEfforts?.["grok-4.6"]) + .toBe("high"); + expect(config.providers.xai.note).toBe("user-owned-note"); + expect(reconcileOAuthProviders(config)).toBe(false); + + config.providers.xai.modelDefaultReasoningEfforts = { "grok-4.6": "medium" }; + expect(reconcileOAuthProviders(config)).toBe(false); + expect(routeModel(config, "xai/grok-4.6").provider.modelDefaultReasoningEfforts?.["grok-4.6"]) + .toBe("medium"); + }); }); diff --git a/tests/provider-registry-parity.test.ts b/tests/provider-registry-parity.test.ts index 5949bbe30b..c5c7e71a93 100644 --- a/tests/provider-registry-parity.test.ts +++ b/tests/provider-registry-parity.test.ts @@ -677,7 +677,7 @@ describe("provider registry parity", () => { expect(OAUTH_PROVIDERS.xai.providerConfig.modelReasoningEfforts?.["grok-4.6"]).toEqual(["low", "medium", "high", "xhigh"]); expect(OAUTH_PROVIDERS.xai.providerConfig.modelReasoningEfforts?.["grok-4.5"]).toEqual(["low", "medium", "high"]); expect(OAUTH_PROVIDERS.xai.providerConfig.modelDefaultReasoningEfforts).toEqual({ "grok-4.6": "high" }); - expect(OAUTH_PROVIDERS.xai.providerConfig.modelReasoningEffortMap?.["grok-4.6"]).toEqual({ max: "xhigh" }); + expect(OAUTH_PROVIDERS.xai.providerConfig.modelReasoningEffortMap).toBeUndefined(); expect(OAUTH_PROVIDERS.xai.providerConfig.noVisionModels).toContain("grok-build-0.1"); const antigravityRegistry = PROVIDER_REGISTRY.find(entry => entry.id === "google-antigravity"); expect(antigravityRegistry?.liveModels).toBe(true); diff --git a/tests/reasoning-effort.test.ts b/tests/reasoning-effort.test.ts index 981ee432b7..e2115beb3f 100644 --- a/tests/reasoning-effort.test.ts +++ b/tests/reasoning-effort.test.ts @@ -128,7 +128,7 @@ describe("provider-specific reasoning effort mapping", () => { expect(mapReasoningEffort(grok45.provider, grok45.modelId, "xhigh")).toBe("high"); }); - test("xAI grok-4.6 heals an old persisted API-key ladder without changing grok-4.5", () => { + test("xAI grok-4.6 preserves an explicit narrower ladder and provider-wide downgrade map", () => { const config: OcxConfig = { port: 10100, defaultProvider: "xai", @@ -142,14 +142,16 @@ describe("provider-specific reasoning effort mapping", () => { "grok-4.6": ["low", "medium", "high"], "grok-4.5": ["low", "medium", "high"], }, + reasoningEffortMap: { xhigh: "high", max: "high" }, }, }, }; const grok46 = routeModel(config, "xai/grok-4.6"); const grok45 = routeModel(config, "xai/grok-4.5"); - expect(configuredReasoningEfforts(grok46.provider, grok46.modelId)).toEqual(["low", "medium", "high", "xhigh"]); - expect(mapReasoningEffort(grok46.provider, grok46.modelId, "xhigh")).toBe("xhigh"); + expect(configuredReasoningEfforts(grok46.provider, grok46.modelId)).toEqual(["low", "medium", "high"]); + expect(mapReasoningEffort(grok46.provider, grok46.modelId, "xhigh")).toBe("high"); + expect(mapReasoningEffort(grok46.provider, grok46.modelId, "max")).toBe("high"); expect(configuredReasoningEfforts(grok45.provider, grok45.modelId)).toEqual(["low", "medium", "high"]); expect(mapReasoningEffort(grok45.provider, grok45.modelId, "xhigh")).toBe("high"); });