Files
OmniRoute/open-sse/utils/cursorAgentProtobuf/requestedModelParameters.ts
backryun 6795783228 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.
2026-09-03 07:50:41 -03:00

114 lines
3.7 KiB
TypeScript

export const CURSOR_EFFORT_SUFFIXES = ["low", "medium", "high", "xhigh", "max"] as const;
type CursorRequestedModel = {
modelId: string;
parameters: Array<{ id: string; value: string }>;
};
const CURSOR_ONE_MILLION_SUFFIX = "-1m";
const CURSOR_GPT_REASONING_LEVELS = ["none", ...CURSOR_EFFORT_SUFFIXES] as const;
const CURSOR_CLAUDE_ONE_MILLION_FAMILIES = [
{
legacyPrefix: "claude-fable-5-1",
modelId: "claude-fable-5-1",
supportsFast: false,
trailingThinking: false,
},
{
legacyPrefix: "claude-opus-5",
modelId: "claude-opus-5",
supportsFast: true,
trailingThinking: false,
},
{
legacyPrefix: "claude-opus-4-8",
modelId: "claude-opus-4-8",
supportsFast: true,
trailingThinking: false,
},
{
legacyPrefix: "claude-sonnet-5",
modelId: "claude-sonnet-5",
supportsFast: false,
trailingThinking: false,
},
{
legacyPrefix: "claude-4.6-sonnet",
modelId: "claude-sonnet-4-6",
supportsFast: false,
trailingThinking: true,
},
] as const;
type CursorClaudeOneMillionFamily = (typeof CURSOR_CLAUDE_ONE_MILLION_FAMILIES)[number];
function isCursorEffort(value: string): value is (typeof CURSOR_EFFORT_SUFFIXES)[number] {
return CURSOR_EFFORT_SUFFIXES.some((effort) => effort === value);
}
function resolveGptOneMillionContextModel(legacyId: string): CursorRequestedModel | null {
const match = /^(gpt-5\.6-(?:sol|terra|luna))-(none|low|medium|high|xhigh|max)$/.exec(legacyId);
if (!match) return null;
const [, modelId, reasoning] = match;
if (!CURSOR_GPT_REASONING_LEVELS.some((level) => level === reasoning)) return null;
return {
modelId,
parameters: [
{ id: "context", value: "1m" },
{ id: "reasoning", value: reasoning },
{ id: "fast", value: "false" },
],
};
}
function resolveClaudeOneMillionVariant(
legacyId: string,
family: CursorClaudeOneMillionFamily
): CursorRequestedModel | null {
const prefix = `${family.legacyPrefix}-`;
if (!legacyId.startsWith(prefix)) return null;
let variant = legacyId.slice(prefix.length);
const fast = variant.endsWith("-fast");
if (fast) variant = variant.slice(0, -"-fast".length);
if (fast && !family.supportsFast) return null;
const trailingThinking = family.trailingThinking && variant.endsWith("-thinking");
const leadingThinking = !family.trailingThinking && variant.startsWith("thinking-");
if (trailingThinking) variant = variant.slice(0, -"-thinking".length);
if (leadingThinking) variant = variant.slice("thinking-".length);
if (!isCursorEffort(variant)) return null;
const parameters = [
{ id: "thinking", value: String(trailingThinking || leadingThinking) },
{ id: "context", value: "1m" },
{ id: "effort", value: variant },
];
if (family.supportsFast) parameters.push({ id: "fast", value: String(fast) });
return { modelId: family.modelId, parameters };
}
function resolveClaudeOneMillionContextModel(legacyId: string): CursorRequestedModel | null {
for (const family of CURSOR_CLAUDE_ONE_MILLION_FAMILIES) {
const resolved = resolveClaudeOneMillionVariant(legacyId, family);
if (resolved) return resolved;
}
return null;
}
/**
* Cursor reuses each legacy slug for both its default and 1M context variants,
* so the public catalog adds a terminal `-1m` discriminator. Translate that
* synthetic id to the canonical wire model plus the complete parameter set
* reported by Cursor's AvailableModels metadata.
*/
export function resolveOneMillionContextModel(normalized: string): CursorRequestedModel | null {
if (!normalized.endsWith(CURSOR_ONE_MILLION_SUFFIX)) return null;
const legacyId = normalized.slice(0, -CURSOR_ONE_MILLION_SUFFIX.length);
return (
resolveGptOneMillionContextModel(legacyId) ?? resolveClaudeOneMillionContextModel(legacyId)
);
}