mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-18 12:52:25 +03:00
feat(providers): refresh Fable, Cursor, and Devin catalogs (#12367)
Validado em lote numa worktree combinada com #12524, #12538, #12277 e #12367 sobre o tip de release/v3.8.51: os quatro boardaram sem conflito (áreas disjuntas — zai-web, nvidia, clova, cursor/devin/fable). typecheck:core limpo, check:provider-consistency OK (272 entradas REGISTRY, 355 providers canônicos), check:known-symbols OK, e 305/305 nos testes tocados pelos quatro PRs. Os IDs de modelo adicionados foram conferidos individualmente. Obrigado, @backryun.
This commit is contained in:
@@ -45,7 +45,7 @@ export const CLI_TOOLS: Record<string, CliCatalogEntry> = {
|
||||
name: "Claude Fable",
|
||||
alias: "fable",
|
||||
envKey: "ANTHROPIC_DEFAULT_FABLE_MODEL",
|
||||
defaultValue: _cc.fable ? `cc/${_cc.fable}` : "cc/claude-fable-5",
|
||||
defaultValue: _cc.fable ? `cc/${_cc.fable}` : "cc/claude-fable-5-1",
|
||||
isTopLevel: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -24,9 +24,13 @@ export interface ModelSpec {
|
||||
// Model ONLY supports adaptive thinking: manual extended thinking was removed. Sending
|
||||
// `thinking.type:"enabled"` or any `thinking.budget_tokens` returns HTTP 400; reasoning
|
||||
// is steered exclusively by `output_config.effort` (low/medium/high/xhigh/max). True for
|
||||
// Claude Opus 4.7 and later (Opus 4.7/4.8/5, Fable 5). Per Anthropic's migration guide,
|
||||
// Claude Opus 4.7 and later (Opus 4.7/4.8/5, Fable 5/5.1). Per Anthropic's migration guide,
|
||||
// any request that tries to set a fixed thinking budget gets a 400 error.
|
||||
adaptiveThinkingOnly?: boolean;
|
||||
// The model rejects tool_choice values that require a tool call. Keep tools available,
|
||||
// but normalize a forced choice to the default auto behavior before dispatch. Fable 5.1 always runs
|
||||
// adaptive thinking, so forced tool use cannot be combined with any valid request.
|
||||
rejectsForcedToolChoice?: boolean;
|
||||
// Highest effort accepted while `thinking.type:"disabled"` is present. Claude Opus 5
|
||||
// rejects disabled thinking with xhigh/max, while accepting it through high.
|
||||
maxEffortWhenThinkingDisabled?: "high";
|
||||
@@ -371,6 +375,21 @@ export const MODEL_SPECS: Record<string, ModelSpec> = {
|
||||
aliases: BEDROCK_CLAUDE_ALIASES("claude-opus-4-7", "claude-opus-4.7"),
|
||||
},
|
||||
|
||||
// ── Claude Fable 5.1 ────────────────────────────────────────────
|
||||
"claude-fable-5-1": {
|
||||
maxOutputTokens: 128000,
|
||||
contextWindow: 1000000,
|
||||
defaultThinkingBudget: 32000,
|
||||
thinkingBudgetCap: 120000,
|
||||
supportsThinking: true,
|
||||
supportsTools: true,
|
||||
supportsVision: true,
|
||||
rejectsThinkingDisabled: true,
|
||||
adaptiveThinkingOnly: true,
|
||||
rejectsForcedToolChoice: true,
|
||||
aliases: BEDROCK_CLAUDE_ALIASES("claude-fable-5-1"),
|
||||
},
|
||||
|
||||
// ── Claude Fable 5 ──────────────────────────────────────────────
|
||||
"claude-fable-5": {
|
||||
maxOutputTokens: 128000,
|
||||
@@ -849,9 +868,39 @@ export function normalizeThinkingForModel<T extends Record<string, unknown>>(
|
||||
getModelSpec(modelId)?.rejectsThinkingDisabled
|
||||
) {
|
||||
const { thinking: _omitted, ...rest } = body as Record<string, unknown>;
|
||||
return rest as T;
|
||||
return normalizeForcedToolChoiceForModel(rest as T, modelId);
|
||||
}
|
||||
return body;
|
||||
return normalizeForcedToolChoiceForModel(body, modelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize tool-choice constraints that a resolved model cannot accept.
|
||||
*
|
||||
* Claude Fable 5.1 always uses adaptive thinking and rejects tool choices that force
|
||||
* either any tool or one named tool. Preserve the declared tools and every unrelated
|
||||
* request field, but drop the choice to select the default `auto` behavior so routing a
|
||||
* request to Fable 5.1 does not turn a recoverable preference into an upstream 400.
|
||||
*/
|
||||
export function normalizeForcedToolChoiceForModel<T extends Record<string, unknown>>(
|
||||
body: T,
|
||||
modelId: string
|
||||
): T {
|
||||
if (!getModelSpec(modelId)?.rejectsForcedToolChoice) return body;
|
||||
|
||||
const toolChoice = body.tool_choice;
|
||||
const forced =
|
||||
toolChoice === "required" ||
|
||||
toolChoice === "any" ||
|
||||
(toolChoice !== null &&
|
||||
typeof toolChoice === "object" &&
|
||||
!Array.isArray(toolChoice) &&
|
||||
["any", "tool", "function"].includes(
|
||||
String((toolChoice as Record<string, unknown>).type || "").toLowerCase()
|
||||
));
|
||||
if (!forced) return body;
|
||||
|
||||
const { tool_choice: _omitted, ...rest } = body;
|
||||
return rest as T;
|
||||
}
|
||||
|
||||
export function capMaxOutputTokens(modelId: string, requested?: number): number | undefined {
|
||||
|
||||
@@ -7,10 +7,12 @@ import { DEFAULT_PRICING_OAUTH } from "./oauth-subscriptions";
|
||||
import { DEFAULT_PRICING_FRONTIER } from "./frontier-labs";
|
||||
import { DEFAULT_PRICING_INFERENCE } from "./inference-hosts";
|
||||
import { DEFAULT_PRICING_REGIONAL } from "./regional";
|
||||
import { DEFAULT_PRICING_DEVIN } from "./devin";
|
||||
|
||||
export const DEFAULT_PRICING = {
|
||||
...DEFAULT_PRICING_OAUTH,
|
||||
...DEFAULT_PRICING_FRONTIER,
|
||||
...DEFAULT_PRICING_INFERENCE,
|
||||
...DEFAULT_PRICING_REGIONAL,
|
||||
...DEFAULT_PRICING_DEVIN,
|
||||
};
|
||||
|
||||
142
src/shared/constants/pricing/devin.ts
Normal file
142
src/shared/constants/pricing/devin.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
type DevinTokenPricing = {
|
||||
input: number;
|
||||
cached: number;
|
||||
output: number;
|
||||
};
|
||||
|
||||
const QUALITY_EFFORTS = ["max", "xhigh", "high", "medium", "low"] as const;
|
||||
const GPT_EFFORTS = ["max", "xhigh", "high", "medium", "low", "none"] as const;
|
||||
|
||||
function variantIds(base: string, efforts: readonly string[]): string[] {
|
||||
return efforts.map((effort) => `${base}-${effort}`);
|
||||
}
|
||||
|
||||
function fastVariantIds(base: string): string[] {
|
||||
return QUALITY_EFFORTS.map((effort) => `${base}-${effort}-fast`);
|
||||
}
|
||||
|
||||
function priorityVariantIds(base: string): string[] {
|
||||
return GPT_EFFORTS.map((effort) => `${base}-${effort}-priority`);
|
||||
}
|
||||
|
||||
function priced(ids: readonly string[], pricing: DevinTokenPricing) {
|
||||
return Object.fromEntries(ids.map((id) => [id, pricing]));
|
||||
}
|
||||
|
||||
const CLAUDE_FABLE_5_1 = { input: 10, cached: 0.25, output: 50 };
|
||||
const CLAUDE_OPUS = { input: 5, cached: 0.5, output: 25 };
|
||||
const CLAUDE_OPUS_FAST = { input: 10, cached: 1, output: 50 };
|
||||
const CLAUDE_SONNET_5 = { input: 2, cached: 0.2, output: 10 };
|
||||
const CLAUDE_SONNET_4_6 = { input: 3, cached: 0.3, output: 15 };
|
||||
const CLAUDE_HAIKU_4_5 = { input: 1, cached: 0.1, output: 5 };
|
||||
|
||||
const GPT_5_6_SOL = { input: 4, cached: 0.4, output: 20 };
|
||||
const GPT_5_6_SOL_FAST = { input: 8, cached: 0.8, output: 40 };
|
||||
const GPT_5_6_TERRA = { input: 2, cached: 0.2, output: 12 };
|
||||
const GPT_5_6_TERRA_FAST = { input: 4, cached: 0.4, output: 24 };
|
||||
const GPT_5_6_LUNA = { input: 0.2, cached: 0.02, output: 1.2 };
|
||||
const GPT_5_6_LUNA_FAST = { input: 0.4, cached: 0.04, output: 2.4 };
|
||||
|
||||
/**
|
||||
* Exact per-UID rates returned by Devin's authenticated live catalog on
|
||||
* 2026-09-02. Rates are USD per one million tokens.
|
||||
*/
|
||||
export const DEVIN_MODEL_PRICING: Record<string, DevinTokenPricing> = {
|
||||
...priced(variantIds("claude-fable-5-1", QUALITY_EFFORTS), CLAUDE_FABLE_5_1),
|
||||
...priced(variantIds("claude-opus-5", QUALITY_EFFORTS), CLAUDE_OPUS),
|
||||
...priced(fastVariantIds("claude-opus-5"), CLAUDE_OPUS_FAST),
|
||||
...priced(variantIds("claude-opus-4-8", QUALITY_EFFORTS), CLAUDE_OPUS),
|
||||
...priced(fastVariantIds("claude-opus-4-8"), CLAUDE_OPUS_FAST),
|
||||
...priced(variantIds("claude-sonnet-5", QUALITY_EFFORTS), CLAUDE_SONNET_5),
|
||||
...priced(
|
||||
[
|
||||
"claude-sonnet-4-6",
|
||||
"claude-sonnet-4-6-thinking",
|
||||
"claude-sonnet-4-6-1m",
|
||||
"claude-sonnet-4-6-thinking-1m",
|
||||
],
|
||||
CLAUDE_SONNET_4_6
|
||||
),
|
||||
MODEL_PRIVATE_11: CLAUDE_HAIKU_4_5,
|
||||
|
||||
...priced(variantIds("gpt-5-6-sol", GPT_EFFORTS), GPT_5_6_SOL),
|
||||
...priced(priorityVariantIds("gpt-5-6-sol"), GPT_5_6_SOL_FAST),
|
||||
...priced(variantIds("gpt-5-6-terra", GPT_EFFORTS), GPT_5_6_TERRA),
|
||||
...priced(priorityVariantIds("gpt-5-6-terra"), GPT_5_6_TERRA_FAST),
|
||||
...priced(variantIds("gpt-5-6-luna", GPT_EFFORTS), GPT_5_6_LUNA),
|
||||
...priced(priorityVariantIds("gpt-5-6-luna"), GPT_5_6_LUNA_FAST),
|
||||
|
||||
...priced(variantIds("kimi-k3", ["max", "high", "low"]), {
|
||||
input: 3,
|
||||
cached: 0.3,
|
||||
output: 15,
|
||||
}),
|
||||
"kimi-k2-7": { input: 0.95, cached: 0.19, output: 4 },
|
||||
...priced(variantIds("glm-5-3", ["max", "high", "low"]), {
|
||||
input: 1.4,
|
||||
cached: 0.26,
|
||||
output: 4.4,
|
||||
}),
|
||||
...priced(variantIds("glm-5-3-flash", ["max", "high", "low"]), {
|
||||
input: 0.15,
|
||||
cached: 0.03,
|
||||
output: 0.5,
|
||||
}),
|
||||
|
||||
...priced(["swe-1-7", "swe-1-7-medium"], {
|
||||
input: 0.5,
|
||||
cached: 0.2,
|
||||
output: 2.5,
|
||||
}),
|
||||
...priced(["swe-1-7-lightning", "swe-1-7-lightning-medium"], {
|
||||
input: 2.5,
|
||||
cached: 1,
|
||||
output: 12.5,
|
||||
}),
|
||||
adaptive: { input: 0.5, cached: 0.1, output: 2 },
|
||||
...priced(variantIds("grok-4-6", ["xhigh", "high", "medium", "low"]), {
|
||||
input: 2,
|
||||
cached: 0.3,
|
||||
output: 6,
|
||||
}),
|
||||
...priced(variantIds("inkling", ["max", "xhigh", "high", "medium", "low", "none"]), {
|
||||
input: 1.4,
|
||||
cached: 0.26,
|
||||
output: 4.4,
|
||||
}),
|
||||
...priced(variantIds("deepseek-v4-flash", ["max", "high", "low"]), {
|
||||
input: 0.14,
|
||||
cached: 0.03,
|
||||
output: 0.28,
|
||||
}),
|
||||
...priced(variantIds("nemotron-3-ultra", ["high", "medium", "none"]), {
|
||||
input: 0.6,
|
||||
cached: 0.12,
|
||||
output: 2.4,
|
||||
}),
|
||||
...priced(variantIds("gemini-3-7-flash", ["high", "medium", "low"]), {
|
||||
input: 1.5,
|
||||
cached: 0.15,
|
||||
output: 7.5,
|
||||
}),
|
||||
...priced(variantIds("gemini-3-1-pro", ["high", "low"]), {
|
||||
input: 2,
|
||||
cached: 0.2,
|
||||
output: 12,
|
||||
}),
|
||||
...priced(variantIds("deepseek-v4-pro", ["max", "high", "low"]), {
|
||||
input: 1.32,
|
||||
cached: 0.04,
|
||||
output: 3.96,
|
||||
}),
|
||||
};
|
||||
|
||||
// Each transport gets its own provider namespace. They share today's upstream
|
||||
// rate snapshot, but can diverge independently if Devin changes one channel.
|
||||
export const DEFAULT_PRICING_DEVIN = {
|
||||
"devin-cli": { ...DEVIN_MODEL_PRICING },
|
||||
dv: { ...DEVIN_MODEL_PRICING },
|
||||
"devin-desktop": { ...DEVIN_MODEL_PRICING },
|
||||
"devin-cli-agentic": { ...DEVIN_MODEL_PRICING },
|
||||
dva: { ...DEVIN_MODEL_PRICING },
|
||||
};
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
GPT_5_6_LUNA_PRICING,
|
||||
GPT_5_6_SOL_PRICING,
|
||||
GPT_5_6_TERRA_PRICING,
|
||||
CLAUDE_FABLE_5_1_PRICING,
|
||||
CLAUDE_FABLE_5_PRICING,
|
||||
CLAUDE_OPUS_5_PRICING,
|
||||
CLAUDE_OPUS_4_PRICING,
|
||||
@@ -213,6 +214,7 @@ export const DEFAULT_PRICING_FRONTIER = {
|
||||
// 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-fable-5-1": CLAUDE_FABLE_5_1_PRICING,
|
||||
"claude-fable-5": CLAUDE_FABLE_5_PRICING,
|
||||
"claude-opus-5": CLAUDE_OPUS_5_PRICING,
|
||||
"claude-sonnet-5": CLAUDE_SONNET_5_PRICING,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Pure data; merged by default-pricing.ts via spread (god-file decomposition; semantic split).
|
||||
*/
|
||||
import {
|
||||
CLAUDE_FABLE_5_1_PRICING,
|
||||
CLAUDE_OPUS_5_PRICING,
|
||||
GEMINI_3_7_FLASH_PROMO_PRICING,
|
||||
GPT_5_3_CODEX_PRICING,
|
||||
@@ -20,6 +21,7 @@ const ANTIGRAVITY_GEMINI_3_7_PRICING = {
|
||||
|
||||
export const DEFAULT_PRICING_OAUTH = {
|
||||
cc: {
|
||||
"claude-fable-5-1": CLAUDE_FABLE_5_1_PRICING,
|
||||
"claude-fable-5": {
|
||||
input: 10.0,
|
||||
output: 50.0,
|
||||
|
||||
@@ -60,6 +60,14 @@ export const CLAUDE_FABLE_5_PRICING = {
|
||||
cache_creation: 15.0,
|
||||
};
|
||||
|
||||
export const CLAUDE_FABLE_5_1_PRICING = {
|
||||
input: 10.0,
|
||||
output: 50.0,
|
||||
cached: 0.25,
|
||||
reasoning: 50.0,
|
||||
cache_creation: 12.5,
|
||||
};
|
||||
|
||||
export const CLAUDE_OPUS_5_PRICING = {
|
||||
input: 5.0,
|
||||
output: 25.0,
|
||||
|
||||
Reference in New Issue
Block a user