mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
feat(claude): default xhigh support for newer Opus models (#2874)
Integrated into release/v3.8.6.
This commit is contained in:
@@ -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",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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 };
|
||||
|
||||
73
tests/unit/claude-fast-mode.test.ts
Normal file
73
tests/unit/claude-fast-mode.test.ts
Normal 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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user