import { CLAUDE_CODE_EFFORT_OPTIONS, CODEX_REASONING_EFFORT_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 ClaudeModelOptions, type ClaudeCodeEffort, type CodexModelOptions, type CodexReasoningEffort, type ModelSlug, type ProviderReasoningEffort, type ProviderKind, } from "@t3tools/contracts"; const MODEL_SLUG_SET_BY_PROVIDER: Record> = { claudeAgent: new Set(MODEL_OPTIONS_BY_PROVIDER.claudeAgent.map((option) => option.slug)), codex: new Set(MODEL_OPTIONS_BY_PROVIDER.codex.map((option) => option.slug)), }; const CLAUDE_OPUS_4_6_MODEL = "claude-opus-4-6"; const CLAUDE_SONNET_4_6_MODEL = "claude-sonnet-4-6"; const CLAUDE_HAIKU_4_5_MODEL = "claude-haiku-4-5"; export function getModelOptions(provider: ProviderKind = "codex") { return MODEL_OPTIONS_BY_PROVIDER[provider]; } export function getDefaultModel(provider: ProviderKind = "codex"): ModelSlug { return DEFAULT_MODEL_BY_PROVIDER[provider]; } export function supportsClaudeFastMode(model: string | null | undefined): boolean { return normalizeModelSlug(model, "claudeAgent") === CLAUDE_OPUS_4_6_MODEL; } export function supportsClaudeAdaptiveReasoning(model: string | null | undefined): boolean { const normalized = normalizeModelSlug(model, "claudeAgent"); return normalized === CLAUDE_OPUS_4_6_MODEL || normalized === CLAUDE_SONNET_4_6_MODEL; } export function supportsClaudeMaxEffort(model: string | null | undefined): boolean { return normalizeModelSlug(model, "claudeAgent") === CLAUDE_OPUS_4_6_MODEL; } export function supportsClaudeUltrathinkKeyword(model: string | null | undefined): boolean { return supportsClaudeAdaptiveReasoning(model); } export function supportsClaudeThinkingToggle(model: string | null | undefined): boolean { return normalizeModelSlug(model, "claudeAgent") === CLAUDE_HAIKU_4_5_MODEL; } 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 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 inferProviderForModel( model: string | null | undefined, fallback: ProviderKind = "codex", ): ProviderKind { const normalizedClaude = normalizeModelSlug(model, "claudeAgent"); if (normalizedClaude && MODEL_SLUG_SET_BY_PROVIDER.claudeAgent.has(normalizedClaude)) { return "claudeAgent"; } const normalizedCodex = normalizeModelSlug(model, "codex"); if (normalizedCodex && MODEL_SLUG_SET_BY_PROVIDER.codex.has(normalizedCodex)) { return "codex"; } return typeof model === "string" && model.trim().startsWith("claude-") ? "claudeAgent" : fallback; } export function getReasoningEffortOptions(provider: "codex"): ReadonlyArray; export function getReasoningEffortOptions( provider: "claudeAgent", model?: string | null | undefined, ): ReadonlyArray; export function getReasoningEffortOptions( provider?: ProviderKind, model?: string | null | undefined, ): ReadonlyArray; export function getReasoningEffortOptions( provider: ProviderKind = "codex", model?: string | null | undefined, ): ReadonlyArray { if (provider === "claudeAgent") { if (supportsClaudeMaxEffort(model)) { return ["low", "medium", "high", "max", "ultrathink"]; } if (supportsClaudeAdaptiveReasoning(model)) { return ["low", "medium", "high", "ultrathink"]; } return []; } return REASONING_EFFORT_OPTIONS_BY_PROVIDER[provider]; } export function getDefaultReasoningEffort(provider: "codex"): CodexReasoningEffort; export function getDefaultReasoningEffort(provider: "claudeAgent"): ClaudeCodeEffort; export function getDefaultReasoningEffort(provider?: ProviderKind): ProviderReasoningEffort; export function getDefaultReasoningEffort( provider: ProviderKind = "codex", ): ProviderReasoningEffort { return DEFAULT_REASONING_EFFORT_BY_PROVIDER[provider]; } export function resolveReasoningEffortForProvider( provider: "codex", effort: string | null | undefined, ): CodexReasoningEffort | null; export function resolveReasoningEffortForProvider( provider: "claudeAgent", effort: string | null | undefined, ): ClaudeCodeEffort | null; export function resolveReasoningEffortForProvider( provider: ProviderKind, effort: string | null | undefined, ): ProviderReasoningEffort | null; export function resolveReasoningEffortForProvider( provider: ProviderKind, effort: string | null | undefined, ): ProviderReasoningEffort | null { if (typeof effort !== "string") { return null; } const trimmed = effort.trim(); if (!trimmed) { return null; } const options = REASONING_EFFORT_OPTIONS_BY_PROVIDER[provider] as ReadonlyArray; return options.includes(trimmed) ? (trimmed as ProviderReasoningEffort) : null; } export function getEffectiveClaudeCodeEffort( effort: ClaudeCodeEffort | null | undefined, ): Exclude | null { if (!effort) { return null; } return effort === "ultrathink" ? null : effort; } export function normalizeCodexModelOptions( modelOptions: CodexModelOptions | null | undefined, ): CodexModelOptions | undefined { const defaultReasoningEffort = getDefaultReasoningEffort("codex"); const reasoningEffort = resolveReasoningEffortForProvider("codex", modelOptions?.reasoningEffort) ?? defaultReasoningEffort; const fastModeEnabled = modelOptions?.fastMode === true; const nextOptions: CodexModelOptions = { ...(reasoningEffort !== defaultReasoningEffort ? { reasoningEffort } : {}), ...(fastModeEnabled ? { fastMode: true } : {}), }; return Object.keys(nextOptions).length > 0 ? nextOptions : undefined; } export function normalizeClaudeModelOptions( model: string | null | undefined, modelOptions: ClaudeModelOptions | null | undefined, ): ClaudeModelOptions | undefined { const reasoningOptions = getReasoningEffortOptions("claudeAgent", model); const defaultReasoningEffort = getDefaultReasoningEffort("claudeAgent"); const resolvedEffort = resolveReasoningEffortForProvider("claudeAgent", modelOptions?.effort); const effort = resolvedEffort && resolvedEffort !== "ultrathink" && reasoningOptions.includes(resolvedEffort) && resolvedEffort !== defaultReasoningEffort ? resolvedEffort : undefined; const thinking = supportsClaudeThinkingToggle(model) && modelOptions?.thinking === false ? false : undefined; const fastMode = supportsClaudeFastMode(model) && modelOptions?.fastMode === true ? true : undefined; const nextOptions: ClaudeModelOptions = { ...(thinking === false ? { thinking: false } : {}), ...(effort ? { effort } : {}), ...(fastMode ? { fastMode: true } : {}), }; return Object.keys(nextOptions).length > 0 ? nextOptions : undefined; } 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}`; } export { CLAUDE_CODE_EFFORT_OPTIONS, CODEX_REASONING_EFFORT_OPTIONS };