import { Schema } from "effect"; import type { ProviderKind } from "./orchestration"; export const CODEX_REASONING_EFFORT_OPTIONS = ["xhigh", "high", "medium", "low"] as const; export type CodexReasoningEffort = (typeof CODEX_REASONING_EFFORT_OPTIONS)[number]; export const CLAUDE_CODE_EFFORT_OPTIONS = ["low", "medium", "high", "max", "ultrathink"] as const; export type ClaudeCodeEffort = (typeof CLAUDE_CODE_EFFORT_OPTIONS)[number]; export type ProviderReasoningEffort = CodexReasoningEffort | ClaudeCodeEffort; export const CodexModelOptions = Schema.Struct({ reasoningEffort: Schema.optional(Schema.Literals(CODEX_REASONING_EFFORT_OPTIONS)), fastMode: Schema.optional(Schema.Boolean), }); export type CodexModelOptions = typeof CodexModelOptions.Type; export const ClaudeModelOptions = Schema.Struct({ thinking: Schema.optional(Schema.Boolean), effort: Schema.optional(Schema.Literals(CLAUDE_CODE_EFFORT_OPTIONS)), fastMode: Schema.optional(Schema.Boolean), }); export type ClaudeModelOptions = typeof ClaudeModelOptions.Type; export const ProviderModelOptions = Schema.Struct({ codex: Schema.optional(CodexModelOptions), claudeAgent: Schema.optional(ClaudeModelOptions), }); export type ProviderModelOptions = typeof ProviderModelOptions.Type; export type EffortOption = { readonly value: string; readonly label: string; readonly isDefault?: true; }; export type ModelCapabilities = { readonly reasoningEffortLevels: readonly EffortOption[]; readonly supportsFastMode: boolean; readonly supportsThinkingToggle: boolean; readonly promptInjectedEffortLevels: readonly string[]; }; type ModelDefinition = { readonly slug: string; readonly name: string; readonly capabilities: ModelCapabilities; }; /** * TODO: This should not be a static array, each provider * should return its own model list over the WS API. */ export const MODEL_OPTIONS_BY_PROVIDER = { codex: [ { slug: "gpt-5.4", name: "GPT-5.4", capabilities: { reasoningEffortLevels: [ { value: "xhigh", label: "Extra High" }, { value: "high", label: "High", isDefault: true }, { value: "medium", label: "Medium" }, { value: "low", label: "Low" }, ], supportsFastMode: true, supportsThinkingToggle: false, promptInjectedEffortLevels: [], }, }, { slug: "gpt-5.4-mini", name: "GPT-5.4 Mini", capabilities: { reasoningEffortLevels: [ { value: "xhigh", label: "Extra High" }, { value: "high", label: "High", isDefault: true }, { value: "medium", label: "Medium" }, { value: "low", label: "Low" }, ], supportsFastMode: true, supportsThinkingToggle: false, promptInjectedEffortLevels: [], }, }, { slug: "gpt-5.3-codex", name: "GPT-5.3 Codex", capabilities: { reasoningEffortLevels: [ { value: "xhigh", label: "Extra High" }, { value: "high", label: "High", isDefault: true }, { value: "medium", label: "Medium" }, { value: "low", label: "Low" }, ], supportsFastMode: true, supportsThinkingToggle: false, promptInjectedEffortLevels: [], }, }, { slug: "gpt-5.3-codex-spark", name: "GPT-5.3 Codex Spark", capabilities: { reasoningEffortLevels: [ { value: "xhigh", label: "Extra High" }, { value: "high", label: "High", isDefault: true }, { value: "medium", label: "Medium" }, { value: "low", label: "Low" }, ], supportsFastMode: true, supportsThinkingToggle: false, promptInjectedEffortLevels: [], }, }, { slug: "gpt-5.2-codex", name: "GPT-5.2 Codex", capabilities: { reasoningEffortLevels: [ { value: "xhigh", label: "Extra High" }, { value: "high", label: "High", isDefault: true }, { value: "medium", label: "Medium" }, { value: "low", label: "Low" }, ], supportsFastMode: true, supportsThinkingToggle: false, promptInjectedEffortLevels: [], }, }, { slug: "gpt-5.2", name: "GPT-5.2", capabilities: { reasoningEffortLevels: [ { value: "xhigh", label: "Extra High" }, { value: "high", label: "High", isDefault: true }, { value: "medium", label: "Medium" }, { value: "low", label: "Low" }, ], supportsFastMode: true, supportsThinkingToggle: false, promptInjectedEffortLevels: [], }, }, ], claudeAgent: [ { slug: "claude-opus-4-6", name: "Claude Opus 4.6", capabilities: { reasoningEffortLevels: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "max", label: "Max" }, { value: "ultrathink", label: "Ultrathink" }, ], supportsFastMode: true, supportsThinkingToggle: false, promptInjectedEffortLevels: ["ultrathink"], }, }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", capabilities: { reasoningEffortLevels: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "ultrathink", label: "Ultrathink" }, ], supportsFastMode: false, supportsThinkingToggle: false, promptInjectedEffortLevels: ["ultrathink"], }, }, { slug: "claude-haiku-4-5", name: "Claude Haiku 4.5", capabilities: { reasoningEffortLevels: [], supportsFastMode: false, supportsThinkingToggle: true, promptInjectedEffortLevels: [], }, }, ], } as const satisfies Record; export type ModelOptionsByProvider = typeof MODEL_OPTIONS_BY_PROVIDER; type BuiltInModelSlug = (typeof MODEL_OPTIONS_BY_PROVIDER)[ProviderKind][number]["slug"]; export type ModelSlug = BuiltInModelSlug | (string & {}); export const DEFAULT_MODEL_BY_PROVIDER: Record = { codex: "gpt-5.4", claudeAgent: "claude-sonnet-4-6", }; // Backward compatibility for existing Codex-only call sites. export const MODEL_OPTIONS = MODEL_OPTIONS_BY_PROVIDER.codex; export const DEFAULT_MODEL = DEFAULT_MODEL_BY_PROVIDER.codex; /** Per-provider text generation model defaults. */ export const DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER: Record = { codex: "gpt-5.4-mini", claudeAgent: "claude-haiku-4-5", }; export const MODEL_SLUG_ALIASES_BY_PROVIDER: Record> = { codex: { "5.4": "gpt-5.4", "5.3": "gpt-5.3-codex", "gpt-5.3": "gpt-5.3-codex", "5.3-spark": "gpt-5.3-codex-spark", "gpt-5.3-spark": "gpt-5.3-codex-spark", }, claudeAgent: { opus: "claude-opus-4-6", "opus-4.6": "claude-opus-4-6", "claude-opus-4.6": "claude-opus-4-6", "claude-opus-4-6-20251117": "claude-opus-4-6", sonnet: "claude-sonnet-4-6", "sonnet-4.6": "claude-sonnet-4-6", "claude-sonnet-4.6": "claude-sonnet-4-6", "claude-sonnet-4-6-20251117": "claude-sonnet-4-6", haiku: "claude-haiku-4-5", "haiku-4.5": "claude-haiku-4-5", "claude-haiku-4.5": "claude-haiku-4-5", "claude-haiku-4-5-20251001": "claude-haiku-4-5", }, }; // ── Model capabilities index ────────────────────────────────────────── export const MODEL_CAPABILITIES_INDEX = Object.fromEntries( Object.entries(MODEL_OPTIONS_BY_PROVIDER).map(([provider, models]) => [ provider, Object.fromEntries(models.map((m) => [m.slug, m.capabilities])), ]), ) as unknown as Record>; // ── Provider display names ──────────────────────────────────────────── export const PROVIDER_DISPLAY_NAMES: Record = { codex: "Codex", claudeAgent: "Claude", };