import { CODEX_REASONING_EFFORT_OPTIONS, CURSOR_MODEL_FAMILY_OPTIONS, CURSOR_REASONING_OPTIONS, DEFAULT_MODEL_BY_PROVIDER, DEFAULT_REASONING_EFFORT_BY_PROVIDER, MODEL_OPTIONS_BY_PROVIDER, MODEL_SLUG_ALIASES_BY_PROVIDER, REASONING_EFFORT_OPTIONS_BY_PROVIDER, type CodexReasoningEffort, type CursorModelFamily, type CursorModelSlug, type CursorReasoningOption, type ModelSlug, type ProviderKind, } from "../../contracts/src"; type CursorModelCapability = { readonly supportsReasoning: boolean; readonly supportsFast: boolean; readonly supportsThinking: boolean; readonly defaultReasoning: CursorReasoningOption; readonly defaultThinking: boolean; }; const CURSOR_MODEL_CAPABILITY_BY_FAMILY: Record = { auto: { supportsReasoning: false, supportsFast: false, supportsThinking: false, defaultReasoning: "normal", defaultThinking: false, }, "composer-1.5": { supportsReasoning: false, supportsFast: false, supportsThinking: false, defaultReasoning: "normal", defaultThinking: false, }, "composer-1": { supportsReasoning: false, supportsFast: false, supportsThinking: false, defaultReasoning: "normal", defaultThinking: false, }, "gpt-5.3-codex": { supportsReasoning: true, supportsFast: true, supportsThinking: false, defaultReasoning: "normal", defaultThinking: false, }, "gpt-5.3-codex-spark-preview": { supportsReasoning: false, supportsFast: false, supportsThinking: false, defaultReasoning: "normal", defaultThinking: false, }, "opus-4.6": { supportsReasoning: false, supportsFast: false, supportsThinking: true, defaultReasoning: "normal", defaultThinking: true, }, "opus-4.5": { supportsReasoning: false, supportsFast: false, supportsThinking: true, defaultReasoning: "normal", defaultThinking: true, }, "sonnet-4.6": { supportsReasoning: false, supportsFast: false, supportsThinking: true, defaultReasoning: "normal", defaultThinking: true, }, "gemini-3.1-pro": { supportsReasoning: false, supportsFast: false, supportsThinking: false, defaultReasoning: "normal", defaultThinking: false, }, }; const MODEL_SLUG_SET_BY_PROVIDER: Record> = { claudeCode: new Set(MODEL_OPTIONS_BY_PROVIDER.claudeCode.map((option) => option.slug)), codex: new Set(MODEL_OPTIONS_BY_PROVIDER.codex.map((option) => option.slug)), cursor: new Set(MODEL_OPTIONS_BY_PROVIDER.cursor.map((option) => option.slug)), }; const CURSOR_MODEL_FAMILY_SET = new Set( CURSOR_MODEL_FAMILY_OPTIONS.map((option) => option.slug), ); export interface CursorModelSelection { readonly family: CursorModelFamily; readonly reasoning: CursorReasoningOption; readonly fast: boolean; readonly thinking: boolean; } export function getModelOptions(provider: ProviderKind = "codex") { return MODEL_OPTIONS_BY_PROVIDER[provider]; } export function getCursorModelFamilyOptions() { return CURSOR_MODEL_FAMILY_OPTIONS; } export function getCursorModelCapabilities(family: CursorModelFamily) { return CURSOR_MODEL_CAPABILITY_BY_FAMILY[family]; } function fallbackCursorModelFamily(): CursorModelFamily { const fallback = parseCursorModelSelection(DEFAULT_MODEL_BY_PROVIDER.cursor); return fallback.family; } function resolveCursorModelFamily(model: string | null | undefined): CursorModelFamily { const normalized = normalizeModelSlug(model, "cursor"); if (!normalized) { return fallbackCursorModelFamily(); } if ( normalized === "gpt-5.3-codex" || normalized === "gpt-5.3-codex-fast" || normalized === "gpt-5.3-codex-low" || normalized === "gpt-5.3-codex-low-fast" || normalized === "gpt-5.3-codex-high" || normalized === "gpt-5.3-codex-high-fast" || normalized === "gpt-5.3-codex-xhigh" || normalized === "gpt-5.3-codex-xhigh-fast" ) { return "gpt-5.3-codex"; } if (normalized === "sonnet-4.6-thinking") { return "sonnet-4.6"; } if (normalized === "opus-4.6-thinking") { return "opus-4.6"; } if (normalized === "opus-4.5-thinking") { return "opus-4.5"; } return CURSOR_MODEL_FAMILY_SET.has(normalized as CursorModelFamily) ? (normalized as CursorModelFamily) : fallbackCursorModelFamily(); } function resolveCursorReasoning(model: CursorModelSlug): CursorReasoningOption { if (model.includes("-xhigh")) return "xhigh"; if (model.includes("-high")) return "high"; if (model.includes("-low")) return "low"; return "normal"; } export function parseCursorModelSelection(model: string | null | undefined): CursorModelSelection { const family = resolveCursorModelFamily(model); const capability = CURSOR_MODEL_CAPABILITY_BY_FAMILY[family]; const normalized = resolveModelSlugForProvider("cursor", model) as CursorModelSlug; if (capability.supportsReasoning) { return { family, reasoning: resolveCursorReasoning(normalized), fast: normalized.endsWith("-fast"), thinking: false, }; } if (capability.supportsThinking) { return { family, reasoning: capability.defaultReasoning, fast: false, thinking: normalized.endsWith("-thinking"), }; } return { family, reasoning: capability.defaultReasoning, fast: false, thinking: capability.defaultThinking, }; } export function resolveCursorModelFromSelection(input: { readonly family: CursorModelFamily; readonly reasoning?: CursorReasoningOption | null; readonly fast?: boolean; readonly thinking?: boolean; }): CursorModelSlug { const family = resolveCursorModelFamily(input.family); const capability = CURSOR_MODEL_CAPABILITY_BY_FAMILY[family]; if (capability.supportsReasoning) { const reasoning = CURSOR_REASONING_OPTIONS.includes(input.reasoning ?? "normal") ? (input.reasoning ?? "normal") : capability.defaultReasoning; const reasoningSuffix = reasoning === "normal" ? "" : `-${reasoning}`; const fastSuffix = input.fast ? "-fast" : ""; const candidate = `${family}${reasoningSuffix}${fastSuffix}`; return resolveModelSlugForProvider("cursor", candidate) as CursorModelSlug; } if (capability.supportsThinking) { const candidate = input.thinking ? `${family}-thinking` : family; return resolveModelSlugForProvider("cursor", candidate) as CursorModelSlug; } return resolveModelSlugForProvider("cursor", family) as CursorModelSlug; } export function getDefaultModel(provider: ProviderKind = "codex"): ModelSlug { return DEFAULT_MODEL_BY_PROVIDER[provider]; } export function normalizeModelSlug( model: string | null | undefined, provider: ProviderKind = "codex", ): ModelSlug | null { if (typeof model !== "string") { return null; } const trimmed = model.trim(); if (!trimmed) { return null; } return MODEL_SLUG_ALIASES_BY_PROVIDER[provider][trimmed] ?? (trimmed as ModelSlug); } export function resolveModelSlug( model: string | null | undefined, provider: ProviderKind = "codex", ): ModelSlug { const normalized = normalizeModelSlug(model, provider); if (!normalized) { return DEFAULT_MODEL_BY_PROVIDER[provider]; } return MODEL_SLUG_SET_BY_PROVIDER[provider].has(normalized) ? normalized : DEFAULT_MODEL_BY_PROVIDER[provider]; } export function resolveModelSlugForProvider( provider: ProviderKind, model: string | null | undefined, ): ModelSlug { return resolveModelSlug(model, provider); } export function getReasoningEffortOptions( provider: ProviderKind = "codex", ): ReadonlyArray { return REASONING_EFFORT_OPTIONS_BY_PROVIDER[provider]; } export function getDefaultReasoningEffort(provider: "codex"): CodexReasoningEffort; export function getDefaultReasoningEffort(provider: ProviderKind): CodexReasoningEffort | null; export function getDefaultReasoningEffort( provider: ProviderKind = "codex", ): CodexReasoningEffort | null { return DEFAULT_REASONING_EFFORT_BY_PROVIDER[provider]; } export { CODEX_REASONING_EFFORT_OPTIONS };