import { DEFAULT_MODEL_BY_PROVIDER, MODEL_SLUG_ALIASES_BY_PROVIDER, type ClaudeCodeEffort, type ModelCapabilities, type ModelSlug, type ProviderKind, } from "@t3tools/contracts"; export interface SelectableModelOption { slug: string; name: string; } export function getDefaultModel(provider: ProviderKind = "codex"): ModelSlug { return DEFAULT_MODEL_BY_PROVIDER[provider]; } // ── Effort helpers ──────────────────────────────────────────────────── /** Check whether a capabilities object includes a given effort value. */ export function hasEffortLevel(caps: ModelCapabilities, value: string): boolean { return caps.reasoningEffortLevels.some((l) => l.value === value); } /** Return the default effort value for a capabilities object, or null if none. */ export function getDefaultEffort(caps: ModelCapabilities): string | null { return caps.reasoningEffortLevels.find((l) => l.isDefault)?.value ?? null; } export function isClaudeUltrathinkPrompt(text: string | null | undefined): boolean { return typeof text === "string" && /\bultrathink\b/i.test(text); } 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; } const aliases = MODEL_SLUG_ALIASES_BY_PROVIDER[provider] as Record; const aliased = Object.prototype.hasOwnProperty.call(aliases, trimmed) ? aliases[trimmed] : undefined; return typeof aliased === "string" ? aliased : (trimmed as ModelSlug); } export function resolveSelectableModel( provider: ProviderKind, value: string | null | undefined, options: ReadonlyArray, ): ModelSlug | null { if (typeof value !== "string") { return null; } const trimmed = value.trim(); if (!trimmed) { return null; } const direct = options.find((option) => option.slug === trimmed); if (direct) { return direct.slug; } const byName = options.find((option) => option.name.toLowerCase() === trimmed.toLowerCase()); if (byName) { return byName.slug; } const normalized = normalizeModelSlug(trimmed, provider); if (!normalized) { return null; } const resolved = options.find((option) => option.slug === normalized); return resolved ? resolved.slug : null; } 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 normalized; } export function resolveModelSlugForProvider( provider: ProviderKind, model: string | null | undefined, ): ModelSlug { return resolveModelSlug(model, provider); } /** Trim a string, returning null for empty/missing values. */ export function trimOrNull(value: T | null | undefined): T | null { if (typeof value !== "string") return null; const trimmed = value.trim() as T; return trimmed || null; } export function applyClaudePromptEffortPrefix( text: string, effort: ClaudeCodeEffort | null | undefined, ): string { const trimmed = text.trim(); if (!trimmed) { return trimmed; } if (effort !== "ultrathink") { return trimmed; } if (trimmed.startsWith("Ultrathink:")) { return trimmed; } return `Ultrathink:\n${trimmed}`; }