feat(claude): default xhigh support for newer Opus models (#2874)

Integrated into release/v3.8.6.
This commit is contained in:
Randi
2026-05-29 00:44:58 -04:00
committed by GitHub
parent 517c3c6e44
commit 2428ad2bcd
23 changed files with 181 additions and 30 deletions

View File

@@ -100,7 +100,7 @@ Exported for completeness. Strips trailing `/`, deduplicates a trailing `/v1`, a
- `OMNIROUTE_PROVIDER_KEY``"omniroute"` (the key used under `provider.*`).
- `OMNIROUTE_PROVIDER_NPM``"@ai-sdk/openai-compatible"` (the runtime delegate).
- `OPENCODE_CONFIG_SCHEMA``"https://opencode.ai/config.json"`.
- `OMNIROUTE_DEFAULT_OPENCODE_MODELS` — readonly list of 4 default model ids.
- `OMNIROUTE_DEFAULT_OPENCODE_MODELS` — readonly list of default model ids.
## Custom model catalog
@@ -110,10 +110,10 @@ import { createOmniRouteProvider } from "@omniroute/opencode-provider";
createOmniRouteProvider({
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
models: ["auto", "claude-opus-4-7", "gpt-5.5"],
models: ["auto", "claude-opus-4-8", "gpt-5.5"],
modelLabels: {
auto: "Auto-Combo (recommended)",
"claude-opus-4-7": "Claude Opus 4.7",
"claude-opus-4-8": "Claude Opus 4.8",
"gpt-5.5": "GPT-5.5",
},
});

View File

@@ -46,6 +46,7 @@ export const OPENCODE_CONFIG_SCHEMA = "https://opencode.ai/config.json" as const
* with Claude Code passthrough models (`cc/` prefix).
*/
export const OMNIROUTE_DEFAULT_OPENCODE_MODELS = [
"cc/claude-opus-4-8",
"cc/claude-opus-4-7",
"cc/claude-sonnet-4-6",
"cc/claude-haiku-4-5-20251001",
@@ -83,7 +84,8 @@ export interface ModelCapabilities {
* Matches the context lengths used by OmniRoute's provider registry.
*/
export const OMNIROUTE_DEFAULT_MODEL_CONTEXT_LENGTHS: Record<string, number> = {
"cc/claude-opus-4-7": 200_000,
"cc/claude-opus-4-8": 1_000_000,
"cc/claude-opus-4-7": 1_000_000,
"cc/claude-sonnet-4-6": 200_000,
"cc/claude-haiku-4-5-20251001": 200_000,
"claude-opus-4-5-thinking": 200_000,
@@ -100,6 +102,7 @@ export const OMNIROUTE_DEFAULT_MODEL_CONTEXT_LENGTHS: Record<string, number> = {
* model via `OmniRouteProviderOptions.modelCapabilities`.
*/
export const OMNIROUTE_DEFAULT_MODEL_CAPABILITIES: Record<string, ModelCapabilities> = {
"cc/claude-opus-4-8": { attachment: true, reasoning: true, temperature: true, tool_call: true },
"cc/claude-opus-4-7": { attachment: true, reasoning: true, temperature: true, tool_call: true },
"cc/claude-sonnet-4-6": { attachment: true, reasoning: true, temperature: true, tool_call: true },
"cc/claude-haiku-4-5-20251001": { attachment: true, temperature: true, tool_call: true },

View File

@@ -388,6 +388,7 @@ test("createOmniRouteComboConfig includes optional fields when supplied", () =>
test("OMNIROUTE_DEFAULT_OPENCODE_MODELS includes cc/ prefixed models", () => {
const defaults = [...OMNIROUTE_DEFAULT_OPENCODE_MODELS];
assert.ok(defaults.includes("cc/claude-opus-4-8"));
assert.ok(
defaults.some((m) => m.startsWith("cc/")),
"should have cc/ prefixed models"
@@ -413,9 +414,10 @@ test("createOmniRouteProvider emits limit.context on default model entries", ()
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
});
const entry = provider.models["cc/claude-opus-4-7"];
const entry = provider.models["cc/claude-opus-4-8"];
assert.ok(entry.limit, "model entry should have a limit field");
assert.equal(entry.limit!.context, 200_000);
assert.equal(entry.limit!.context, 1_000_000);
assert.equal(provider.models["cc/claude-opus-4-7"].limit!.context, 1_000_000);
});
test("createOmniRouteProvider omits limit.context for unknown model ids", () => {
@@ -480,8 +482,8 @@ test("createOmniRouteProvider emits default capability flags inline with the mod
baseURL: "http://localhost:20128",
apiKey: "sk_omniroute",
});
const entry = provider.models["cc/claude-opus-4-7"];
assert.equal(entry.name, "cc/claude-opus-4-7");
const entry = provider.models["cc/claude-opus-4-8"];
assert.equal(entry.name, "cc/claude-opus-4-8");
assert.equal(entry.attachment, true);
assert.equal(entry.reasoning, true);
assert.equal(entry.temperature, true);

View File

@@ -578,7 +578,7 @@ For the full environment variable reference, see the [README](../README.md).
> The list below is curated from `open-sse/config/providerRegistry.ts` for v3.8.0. Cloud catalogs (Gemini, OpenRouter, etc.) are synced dynamically — for the full live catalog open **Dashboard → Providers → [provider] → Available Models** or call `GET /api/models/catalog`.
**Claude Code (`cc/`)** — Pro/Max OAuth: `cc/claude-opus-4-7`, `cc/claude-opus-4-6`, `cc/claude-opus-4-5-20251101`, `cc/claude-sonnet-4-6`, `cc/claude-sonnet-4-5-20250929`, `cc/claude-haiku-4-5-20251001`
**Claude Code (`cc/`)** — Pro/Max OAuth: `cc/claude-opus-4-8`, `cc/claude-opus-4-7`, `cc/claude-opus-4-6`, `cc/claude-opus-4-5-20251101`, `cc/claude-sonnet-4-6`, `cc/claude-sonnet-4-5-20250929`, `cc/claude-haiku-4-5-20251001`
**Codex (`cx/`)** — Plus/Pro OAuth: `cx/gpt-5.5` (+ effort tiers: `gpt-5.5-xhigh`, `gpt-5.5-high`, `gpt-5.5-medium`, `gpt-5.5-low`), `cx/gpt-5.4`, `cx/gpt-5.4-mini`, `cx/gpt-5.3-codex`, `cx/gpt-5.3-codex-spark`, `cx/gpt-5.2`
@@ -626,7 +626,7 @@ For the full environment variable reference, see the [README](../README.md).
**Other compatible providers** (selected): `cohere`, `databricks`, `snowflake`, `together`, `vertex`, `alibaba`, `alibaba-cn`, `bedrock` (via `aws-bedrock`), `azure-ai`, `openrouter` (passthrough catalog), `siliconflow`, `hyperbolic`, `huggingface`, `featherless-ai`, `cloudflare-ai`, `scaleway`, `deepinfra`, `vercel-ai-gateway`, `bazaarlink`, `friendliai`, `nous-research`, `reka`, `volcengine`, `ai21`, `gigachat`. Each maintains its own model list in `providerRegistry.ts` and can be auto-synced when the provider exposes a `/models` endpoint.
**Note on model IDs:** OmniRoute uses provider-native IDs (`claude-opus-4-7`, `gpt-5.5`, `glm-5.1`, `MiniMax-M2.7`, `kimi-k2.5`, `grok-4.20-0309-reasoning`). Some IDs include dotted versions because that is how the upstream API expects them. If a model is not listed above, run `omniroute models --search <term>` or hit `GET /api/models/catalog` to confirm availability.
**Note on model IDs:** OmniRoute uses provider-native IDs (`claude-opus-4-8`, `gpt-5.5`, `glm-5.1`, `MiniMax-M2.7`, `kimi-k2.5`, `grok-4.20-0309-reasoning`). Some IDs include dotted versions because that is how the upstream API expects them. If a model is not listed above, run `omniroute models --search <term>` or hit `GET /api/models/catalog` to confirm availability.
</details>

View File

@@ -64,5 +64,14 @@ export function supportsXHighEffort(aliasOrId: string, modelId: string): boolean
const providerModels = PROVIDER_MODELS[alias] || PROVIDER_MODELS[aliasOrId];
// Unknown provider (not in registry) — pass through unchanged.
if (!providerModels) return true;
return getProviderModel(alias, modelId)?.supportsXHighEffort === true;
const model = getProviderModel(alias, modelId);
// Claude Code models default to supporting extra-high effort. Keep explicit
// false entries as the unsupported-model list so newly added Claude models do
// not need opt-in flags.
if (alias === "cc") {
return model?.supportsXHighEffort !== false;
}
return model?.supportsXHighEffort === true;
}

View File

@@ -634,10 +634,15 @@ export const REGISTRY: Record<string, RegistryEntry> = {
tokenUrl: "https://console.anthropic.com/v1/oauth/token",
},
models: [
{
id: "claude-opus-4-8",
name: "Claude Opus 4.8",
contextLength: 1000000,
maxOutputTokens: 128000,
},
{
id: "claude-opus-4-7",
name: "Claude Opus 4.7",
supportsXHighEffort: true,
contextLength: 1000000,
maxOutputTokens: 128000,
},

View File

@@ -217,8 +217,8 @@ function hasActiveClaudeThinking(body: Record<string, unknown>): boolean {
* Each rejection burns a combo fallback attempt before reaching a working
* provider. Apply provider-aware sanitation here (after transformRequest, so
* reintroductions by per-provider transforms are also caught) before fetch.
* Models that genuinely support xhigh (registry flag supportsXHighEffort)
* pass through unchanged.
* Models that genuinely support xhigh pass through unchanged. Claude models
* default to xhigh support unless they are marked as legacy unsupported entries.
*/
const MISTRAL_NO_REASONING_EFFORT_PATTERN = /devstral/i;
const GITHUB_NO_REASONING_EFFORT_PATTERN = /(claude|haiku|oswe)/i;

View File

@@ -51,7 +51,7 @@ const CLAUDE_CODE_COMPATIBLE_DEFAULT_SYSTEM_BLOCKS = [
text: "You are a Claude agent, built on Anthropic's Claude Agent SDK.",
},
];
const CONTEXT_1M_SUPPORTED_MODELS = ["claude-opus-4-7", "claude-opus-4-6"];
const CONTEXT_1M_SUPPORTED_MODELS = ["claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6"];
export const CLAUDE_CODE_COMPATIBLE_STAINLESS_TIMEOUT_SECONDS = getStainlessTimeoutSeconds(
process.env
);

View File

@@ -73,6 +73,7 @@ const MODEL_FAMILIES: Record<string, string[]> = {
"gemini-2.5-pro-preview-06-05": ["gemini-2.5-pro", "gemini-2.5-pro-exp-03-25"],
// Claude Opus family
"claude-opus-4-8": ["claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-4-6"],
"claude-opus-4-7": ["claude-opus-4-6", "claude-opus-4-5-20251101", "claude-sonnet-4-6"],
"claude-opus-4-6": ["claude-opus-4-6-thinking", "claude-opus-4-5-20251101", "claude-sonnet-4-6"],
"claude-opus-4-6-thinking": ["claude-opus-4-6", "claude-opus-4-5-20251101"],

View File

@@ -11,6 +11,7 @@ export interface ModelPricing {
export const KNOWN_MODEL_PRICING: Record<string, ModelPricing> = {
"gpt-4o": { inputCostPer1M: 2.5, outputCostPer1M: 10.0, isFree: false },
"gpt-4o-mini": { inputCostPer1M: 0.15, outputCostPer1M: 0.6, isFree: false },
"claude-opus-4-8": { inputCostPer1M: 15.0, outputCostPer1M: 75.0, isFree: false },
"claude-opus-4-7": { inputCostPer1M: 15.0, outputCostPer1M: 75.0, isFree: false },
"claude-sonnet-4-6": { inputCostPer1M: 3.0, outputCostPer1M: 15.0, isFree: false },
"claude-haiku-4-5": { inputCostPer1M: 0.8, outputCostPer1M: 4.0, isFree: false },

View File

@@ -103,7 +103,10 @@ export async function getSettings() {
autoRefreshProviderQuotaInterval: 180,
comboConfigMode: "guided",
codexServiceTier: { enabled: false },
claudeFastMode: { enabled: false, supportedModels: ["claude-opus-4-7", "claude-opus-4-6"] },
claudeFastMode: {
enabled: false,
supportedModels: ["claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6"],
},
codexSessionAffinityTtlMs: 0,
alwaysPreserveClientCache: "auto",
idempotencyWindowMs: 5000,

View File

@@ -6,7 +6,11 @@ type JsonRecord = Record<string, unknown>;
* Mirrors the binary-side gate observed in claude-code v2.1.145 (KT() check):
* only the latest Opus tiers can request the priority service path.
*/
export const CLAUDE_FAST_MODE_DEFAULT_MODELS = ["claude-opus-4-7", "claude-opus-4-6"] as const;
export const CLAUDE_FAST_MODE_DEFAULT_MODELS = [
"claude-opus-4-8",
"claude-opus-4-7",
"claude-opus-4-6",
] as const;
function asRecord(value: unknown): JsonRecord {
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
@@ -39,7 +43,7 @@ export function isClaudeFastModeEnabled(settings: unknown): boolean {
/**
* Returns the configured supported-model list, defaulting to the conservative
* Opus 4-7 / 4-6 pair (matches the binary KT() gate).
* Opus 4-8 / 4-7 / 4-6 set.
*/
export function getClaudeFastModeSupportedModels(settings: unknown): string[] {
const record = asRecord(settings);
@@ -51,7 +55,7 @@ export function getClaudeFastModeSupportedModels(settings: unknown): string[] {
/**
* True when the toggle is on AND the model id prefix-matches a supported model.
* Prefix matching tolerates dated suffixes (e.g. claude-opus-4-7-20260201).
* Prefix matching tolerates dated suffixes (e.g. claude-opus-4-8-20260528).
*/
export function shouldRequestClaudeFastMode(
settings: unknown,

View File

@@ -37,6 +37,7 @@ const STATIC_MODEL_PROVIDERS: Record<string, () => Array<{ id: string; name: str
],
antigravity: () => ANTIGRAVITY_PUBLIC_MODELS.map((model) => ({ ...model })),
claude: () => [
{ id: "claude-opus-4-8", name: "Claude Opus 4.8" },
{ id: "claude-opus-4-7", name: "Claude Opus 4.7" },
{ id: "claude-opus-4-6", name: "Claude Opus 4.6" },
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },

View File

@@ -187,6 +187,20 @@ export const MODEL_SPECS: Record<string, ModelSpec> = {
aliases: BEDROCK_CLAUDE_ALIASES("claude-opus-4-7", "claude-opus-4.7"),
},
// ── Claude Opus 4.8 ─────────────────────────────────────────────
"claude-opus-4-8": {
maxOutputTokens: 128000,
contextWindow: 1000000,
// Opus 4.8 inherits Opus 4.7's adaptive thinking constraints: no fixed
// thinking budget requests, with effort controlled by output_config.
defaultThinkingBudget: 32000,
thinkingBudgetCap: 120000,
supportsThinking: true,
supportsTools: true,
supportsVision: true,
aliases: BEDROCK_CLAUDE_ALIASES("claude-opus-4-8", "claude-opus-4.8"),
},
// ── Claude Sonnet 4.5 ───────────────────────────────────────────
"claude-sonnet-4-5-20250929": {
maxOutputTokens: 64000,

View File

@@ -129,6 +129,13 @@ export const DEFAULT_PRICING = {
// Claude Code (cc)
cc: {
"claude-opus-4-8": {
input: 5.0,
output: 25.0,
cached: 2.5,
reasoning: 25.0,
cache_creation: 5.0,
},
"claude-opus-4-7": {
input: 5.0,
output: 25.0,
@@ -710,6 +717,9 @@ export const DEFAULT_PRICING = {
// Common model IDs (without dates) used across providers
// Intentional duplicates of dot-notation variants (e.g. claude-opus-4.6)
// to cover hyphen-notation IDs (claude-opus-4-6) used by some clients
"claude-opus-4.8": CLAUDE_OPUS_4_PRICING,
"claude-opus-4-8": CLAUDE_OPUS_4_PRICING,
"claude-opus-4-7": CLAUDE_OPUS_4_PRICING,
"claude-opus-4-6": CLAUDE_OPUS_46_PRICING,
"claude-sonnet-4-6": CLAUDE_SONNET_46_PRICING,
"claude-opus-4-5-20251101": CLAUDE_OPUS_4_PRICING,

View File

@@ -101,8 +101,8 @@ test("sanitizeReasoningEffortForProvider: mistral/devstral preserves reasoning w
});
test("sanitizeReasoningEffortForProvider: codex with xhigh passes through unchanged when model supports it", () => {
// codex/gpt-5.5-xhigh and related Claude opus models are flagged
// supportsXHighEffort:true in providerRegistry. They must not be downgraded.
// codex/gpt-5.5-xhigh is flagged supportsXHighEffort:true in providerRegistry.
// Claude Opus 4.7+ models default to xhigh support unless explicitly opted out.
const body = {
model: "gpt-5.5-xhigh",
reasoning_effort: "xhigh",

View File

@@ -18,7 +18,8 @@ const {
CLAUDE_CODE_COMPATIBLE_DEFAULT_MODELS_PATH,
joinClaudeCodeCompatibleUrl,
} = await import("../../open-sse/services/claudeCodeCompatible.ts");
const { getModelsByProviderId } = await import("../../open-sse/config/providerModels.ts");
const { getModelsByProviderId, supportsXHighEffort } =
await import("../../open-sse/config/providerModels.ts");
const { handleChatCore } = await import("../../open-sse/handlers/chatCore.ts");
const { validateProviderApiKey } = await import("../../src/lib/providers/validation.ts");
const providerNodesRoute = await import("../../src/app/api/provider-nodes/route.ts");
@@ -144,8 +145,8 @@ test("buildClaudeCodeCompatibleRequest keeps prior role history while dropping t
});
test("buildClaudeCodeCompatibleRequest preserves xhigh for Claude models that support it", () => {
const xhighModel = getModelsByProviderId("claude").find(
(model) => model.supportsXHighEffort === true
const xhighModel = getModelsByProviderId("claude").find((model) =>
supportsXHighEffort("claude", model.id)
);
assert.ok(xhighModel, "expected at least one Claude model with xhigh support");
const payload = buildClaudeCodeCompatibleRequest({

View File

@@ -11,12 +11,15 @@ const {
resolveClaudeCodeCompatibleMaxTokens,
buildClaudeCodeCompatibleRequest,
} = await import("../../open-sse/services/claudeCodeCompatible.ts");
const { getModelsByProviderId } = await import("../../open-sse/config/providerModels.ts");
const { getModelsByProviderId, supportsXHighEffort } =
await import("../../open-sse/config/providerModels.ts");
function getClaudeEffortFixtures() {
const claudeModels = getModelsByProviderId("claude");
const xhighModel = claudeModels.find((model) => model.supportsXHighEffort === true);
const standardModel = claudeModels.find((model) => model.supportsXHighEffort === false);
const xhighModel = claudeModels.find((model) => supportsXHighEffort("claude", model.id));
const standardModel = claudeModels.find(
(model) => supportsXHighEffort("claude", model.id) === false
);
assert.ok(xhighModel, "expected at least one Claude model with xhigh support");
assert.ok(standardModel, "expected at least one Claude model without xhigh support");
return { xhighModel, standardModel };

View File

@@ -0,0 +1,73 @@
import test from "node:test";
import assert from "node:assert/strict";
const {
shouldRequestClaudeFastMode,
CLAUDE_FAST_MODE_DEFAULT_MODELS,
getClaudeFastModeSupportedModels,
isClaudeFastModeEnabled,
} = await import("../../src/lib/providers/claudeFastMode.ts");
const enabledSettings = { claudeFastMode: true };
const disabledSettings = { claudeFastMode: false };
test("shouldRequestClaudeFastMode returns false when fast mode is disabled", () => {
assert.equal(shouldRequestClaudeFastMode(disabledSettings, "claude-opus-4-8"), false);
assert.equal(shouldRequestClaudeFastMode({}, "claude-opus-4-8"), false);
assert.equal(shouldRequestClaudeFastMode(null, "claude-opus-4-8"), false);
});
test("shouldRequestClaudeFastMode returns false for non-string or empty modelId", () => {
assert.equal(shouldRequestClaudeFastMode(enabledSettings, null), false);
assert.equal(shouldRequestClaudeFastMode(enabledSettings, undefined), false);
assert.equal(shouldRequestClaudeFastMode(enabledSettings, ""), false);
});
test("shouldRequestClaudeFastMode returns true for claude-opus-4-8 exact match", () => {
assert.equal(shouldRequestClaudeFastMode(enabledSettings, "claude-opus-4-8"), true);
});
test("shouldRequestClaudeFastMode prefix-matches claude-opus-4-8 with dated suffix", () => {
assert.equal(shouldRequestClaudeFastMode(enabledSettings, "claude-opus-4-8-20260528"), true);
assert.equal(shouldRequestClaudeFastMode(enabledSettings, "claude-opus-4-8-20260101"), true);
});
test("shouldRequestClaudeFastMode returns true for claude-opus-4-7 and claude-opus-4-6", () => {
assert.equal(shouldRequestClaudeFastMode(enabledSettings, "claude-opus-4-7"), true);
assert.equal(shouldRequestClaudeFastMode(enabledSettings, "claude-opus-4-6"), true);
assert.equal(shouldRequestClaudeFastMode(enabledSettings, "claude-opus-4-7-20250101"), true);
});
test("shouldRequestClaudeFastMode returns false for non-Opus models", () => {
assert.equal(shouldRequestClaudeFastMode(enabledSettings, "claude-sonnet-4-6"), false);
assert.equal(shouldRequestClaudeFastMode(enabledSettings, "claude-haiku-4-5"), false);
assert.equal(shouldRequestClaudeFastMode(enabledSettings, "gpt-4o"), false);
});
test("CLAUDE_FAST_MODE_DEFAULT_MODELS includes claude-opus-4-8", () => {
assert.ok(
CLAUDE_FAST_MODE_DEFAULT_MODELS.includes("claude-opus-4-8"),
"claude-opus-4-8 must be in CLAUDE_FAST_MODE_DEFAULT_MODELS"
);
});
test("getClaudeFastModeSupportedModels returns default list when none configured", () => {
const models = getClaudeFastModeSupportedModels({});
assert.ok(models.includes("claude-opus-4-8"));
assert.ok(models.includes("claude-opus-4-7"));
assert.ok(models.includes("claude-opus-4-6"));
});
test("getClaudeFastModeSupportedModels respects custom override list", () => {
const settings = { claudeFastMode: { enabled: true, supportedModels: ["my-custom-model"] } };
const models = getClaudeFastModeSupportedModels(settings);
assert.deepEqual(models, ["my-custom-model"]);
});
test("isClaudeFastModeEnabled handles boolean and object shape", () => {
assert.equal(isClaudeFastModeEnabled({ claudeFastMode: true }), true);
assert.equal(isClaudeFastModeEnabled({ claudeFastMode: false }), false);
assert.equal(isClaudeFastModeEnabled({ claudeFastMode: { enabled: true } }), true);
assert.equal(isClaudeFastModeEnabled({ claudeFastMode: { enabled: false } }), false);
assert.equal(isClaudeFastModeEnabled({}), false);
});

View File

@@ -10,6 +10,7 @@ import {
getModelsByProviderId,
getProviderModels,
isValidModel,
supportsXHighEffort,
} from "../../open-sse/config/providerModels.ts";
test("provider models helpers expose model lists and defaults", () => {
@@ -90,3 +91,14 @@ test("Kiro registry exposes the current CLI model lineup with context windows",
assert.equal(byId.has("claude-sonnet-4-6"), false);
assert.equal(byId.has("claude-haiku-4-5"), false);
});
test("Claude xhigh effort support defaults on for new models and opts out legacy models", () => {
const claudeModels = new Set(getModelsByProviderId("claude").map((model) => model.id));
assert.ok(claudeModels.has("claude-opus-4-8"));
assert.equal(supportsXHighEffort("claude", "claude-opus-4-8"), true);
assert.equal(supportsXHighEffort("claude", "claude-opus-4-7"), true);
assert.equal(supportsXHighEffort("claude", "claude-opus-4-6"), false);
assert.equal(supportsXHighEffort("claude", "claude-sonnet-4-6"), false);
assert.equal(supportsXHighEffort("claude", "claude-future-5-0"), true);
});

View File

@@ -27,6 +27,10 @@ test("T12: pricing table includes MiniMax, GLM, Kimi and gpt-5.4 mini entries",
assert.ok(pricing.kimi["kimi-k2.5"], "missing kimi/kimi-k2.5");
assert.ok(pricing.kimi["kimi-k2.5-thinking"], "missing kimi/kimi-k2.5-thinking");
assert.ok(pricing.kimi["kimi-for-coding"], "missing kimi/kimi-for-coding");
assert.ok(pricing.anthropic["claude-opus-4.8"], "missing anthropic/claude-opus-4.8");
assert.ok(pricing.anthropic["claude-opus-4-8"], "missing anthropic/claude-opus-4-8");
assert.ok(pricing.anthropic["claude-opus-4-7"], "missing anthropic/claude-opus-4-7");
});
test("T12: codex catalog includes GPT 5.5 variations", () => {

View File

@@ -49,6 +49,7 @@ test("T34: max output tokens are capped by model spec", () => {
assert.equal(capMaxOutputTokens("gemini-3-flash", 131072), 65536);
assert.equal(capMaxOutputTokens("gemini-3-flash"), 65536);
assert.equal(capMaxOutputTokens("gemini-3.1-pro-high", 131072), 65535);
assert.equal(capMaxOutputTokens("claude-opus-4-8", 200000), 128000);
assert.equal(capMaxOutputTokens("claude-opus-4-7", 200000), 128000);
assert.equal(capMaxOutputTokens("anthropic.claude-sonnet-4-6", 200000), 64000);
assert.equal(capMaxOutputTokens("eu.anthropic.claude-opus-4-6", 200000), 128000);
@@ -64,6 +65,7 @@ test("T38: modelSpecs exposes centralized helpers with alias and prefix lookup",
assert.equal(getModelSpec("gemini-3.1-pro-preview").maxOutputTokens, 65535);
assert.equal(getModelSpec("gemini-3.1-pro-preview-customtools").maxOutputTokens, 65535);
assert.equal(getModelSpec("claude-opus-4-7").contextWindow, 1000000);
assert.equal(getModelSpec("claude-opus-4.8").maxOutputTokens, 128000);
assert.equal(getModelSpec("claude-opus-4.7").maxOutputTokens, 128000);
assert.equal(getModelSpec("bedrock/eu.anthropic.claude-sonnet-4-6").contextWindow, 1000000);
assert.equal(getModelSpec("bedrock/anthropic.claude-sonnet-4-5").contextWindow, 200000);

View File

@@ -11,12 +11,15 @@ const {
const { CLAUDE_SYSTEM_PROMPT } = await import("../../open-sse/config/constants.ts");
const { DEFAULT_THINKING_CLAUDE_SIGNATURE } =
await import("../../open-sse/config/defaultThinkingSignature.ts");
const { getModelsByProviderId } = await import("../../open-sse/config/providerModels.ts");
const { getModelsByProviderId, supportsXHighEffort } =
await import("../../open-sse/config/providerModels.ts");
function getClaudeEffortFixtures() {
const claudeModels = getModelsByProviderId("claude");
const xhighModel = claudeModels.find((model) => model.supportsXHighEffort === true);
const standardModel = claudeModels.find((model) => model.supportsXHighEffort === false);
const xhighModel = claudeModels.find((model) => supportsXHighEffort("claude", model.id));
const standardModel = claudeModels.find(
(model) => supportsXHighEffort("claude", model.id) === false
);
assert.ok(xhighModel, "expected at least one Claude model with xhigh support");
assert.ok(standardModel, "expected at least one Claude model without xhigh support");
return { xhighModel, standardModel };