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<CursorModelFamily, CursorModelCapability> = { 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<ProviderKind, ReadonlySet<ModelSlug>> = { 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<CursorModelFamily>( 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<CodexReasoningEffort> { 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 };
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<CursorModelFamily, CursorModelCapability> = {
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<ProviderKind, ReadonlySet<ModelSlug>> = {
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<CursorModelFamily>(
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<CodexReasoningEffort> {
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 };