import { type ClaudeSettings, type ModelCapabilities, type ModelSelection, type ServerProviderModel, type ServerProviderSlashCommand,} from "@t3tools/contracts";import * as DateTime from "effect/DateTime";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem";import * as Option from "effect/Option";import * as Path from "effect/Path";import * as Result from "effect/Result";import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";import { createModelCapabilities, getModelSelectionStringOptionValue, getProviderOptionCurrentValue, getProviderOptionDescriptors,} from "@t3tools/shared/model";import { resolveSpawnCommand } from "@t3tools/shared/shell";import { compareSemverVersions } from "@t3tools/shared/semver";import { query as claudeQuery, type Options as ClaudeQueryOptions, type SlashCommand as ClaudeSlashCommand, type SDKUserMessage, type SettingSource,} from "@anthropic-ai/claude-agent-sdk"; import { buildBooleanOptionDescriptor, buildSelectOptionDescriptor, buildServerProvider, DEFAULT_TIMEOUT_MS, isCommandMissingCause, parseGenericCliVersion, providerModelsFromSettings, spawnAndCollect, type ServerProviderDraft,} from "../providerSnapshot.ts";import { resolveClaudeSdkExecutablePath } from "../Drivers/ClaudeExecutable.ts";import { makeClaudeEnvironment } from "../Drivers/ClaudeHome.ts";import { discoverClaudeSkills } from "../Drivers/ClaudeSkills.ts"; const DEFAULT_CLAUDE_MODEL_CAPABILITIES: ModelCapabilities = createModelCapabilities({ optionDescriptors: [],}); const CLAUDE_PRESENTATION = { displayName: "Claude", showInteractionModeToggle: true,} as const;const MINIMUM_CLAUDE_OPUS_5_VERSION = "2.1.219";const MINIMUM_CLAUDE_FABLE_5_VERSION = "2.1.169";const MINIMUM_CLAUDE_OPUS_4_8_VERSION = "2.1.154";const MINIMUM_CLAUDE_OPUS_4_7_VERSION = "2.1.111"; const CURRENT_CLAUDE_MODELS = new Set(["claude-fable-5", "claude-opus-5", "claude-sonnet-5"]); export function isLegacyClaudeModel(model: string): boolean { return !CURRENT_CLAUDE_MODELS.has(model);} const CLAUDE_MODEL_CATALOG: ReadonlyArray<ServerProviderModel> = [ { slug: "claude-fable-5", name: "Claude Fable 5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "xhigh", label: "Extra High" }, { value: "max", label: "Max" }, { value: "ultracode", label: "Ultracode" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", options: [ { value: "200k", label: "200k" }, { value: "1m", label: "1M", isDefault: true }, ], }), ], }), }, { slug: "claude-opus-5", name: "Claude Opus 5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "xhigh", label: "Extra High" }, { value: "max", label: "Max" }, { value: "ultracode", label: "Ultracode" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", // Claude Code selects the 1M variant explicitly (`claude-opus-5[1m]`). options: [ { value: "200k", label: "200k" }, { value: "1m", label: "1M", isDefault: true }, ], }), ], }), }, { slug: "claude-opus-4-8", name: "Claude Opus 4.8", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "xhigh", label: "Extra High" }, { value: "max", label: "Max" }, { value: "ultracode", label: "Ultracode" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), ], }), }, { slug: "claude-opus-4-7", name: "Claude Opus 4.7", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High" }, { value: "xhigh", label: "Extra High", isDefault: true }, { value: "max", label: "Max" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), ], }), }, { slug: "claude-opus-4-6", name: "Claude Opus 4.6", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "max", label: "Max" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", options: [ { value: "200k", label: "200k" }, { value: "1m", label: "1M", isDefault: true }, ], }), ], }), }, { slug: "claude-opus-4-5", name: "Claude Opus 4.5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "max", label: "Max" }, ], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), ], }), }, { slug: "claude-sonnet-5", name: "Claude Sonnet 5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "xhigh", label: "Extra High" }, { value: "max", label: "Max" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", // Sonnet is 200k-default in Claude Code (1M is opt-in there too). options: [ { value: "200k", label: "200k", isDefault: true }, { value: "1m", label: "1M" }, ], }), ], }), }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "max", label: "Max" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", // Sonnet is 200k-default in Claude Code (1M is opt-in there too). options: [ { value: "200k", label: "200k", isDefault: true }, { value: "1m", label: "1M" }, ], }), ], }), }, { slug: "claude-haiku-4-5", name: "Claude Haiku 4.5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildBooleanOptionDescriptor({ id: "thinking", label: "Thinking", }), ], }), },]; const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = CLAUDE_MODEL_CATALOG.map((model) => isLegacyClaudeModel(model.slug) ? { ...model, isLegacy: true } : model,); function supportsClaudeOpus5(version: string | null | undefined): boolean { return version ? compareSemverVersions(version, MINIMUM_CLAUDE_OPUS_5_VERSION) >= 0 : false;} function supportsClaudeFable5(version: string | null | undefined): boolean { return version ? compareSemverVersions(version, MINIMUM_CLAUDE_FABLE_5_VERSION) >= 0 : false;} function supportsClaudeOpus48(version: string | null | undefined): boolean { return version ? compareSemverVersions(version, MINIMUM_CLAUDE_OPUS_4_8_VERSION) >= 0 : false;} function supportsClaudeOpus47(version: string | null | undefined): boolean { return version ? compareSemverVersions(version, MINIMUM_CLAUDE_OPUS_4_7_VERSION) >= 0 : false;} function getBuiltInClaudeModelsForVersion( version: string | null | undefined,): ReadonlyArray<ServerProviderModel> { return BUILT_IN_MODELS.filter((model) => { if (model.slug === "claude-opus-5") { return supportsClaudeOpus5(version); } if (model.slug === "claude-fable-5") { return supportsClaudeFable5(version); } if (model.slug === "claude-opus-4-8") { return supportsClaudeOpus48(version); } if (model.slug === "claude-opus-4-7") { return supportsClaudeOpus47(version); } return true; });} function formatClaudeOpus5UpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; return `Claude Code ${versionLabel} is too old for Claude Opus 5. Upgrade to v${MINIMUM_CLAUDE_OPUS_5_VERSION} or newer to access it.`;} function formatClaudeFable5UpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; return `Claude Code ${versionLabel} is too old for Claude Fable 5. Upgrade to v${MINIMUM_CLAUDE_FABLE_5_VERSION} or newer to access it.`;} function formatClaudeOpus48UpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; return `Claude Code ${versionLabel} is too old for Claude Opus 4.8. Upgrade to v${MINIMUM_CLAUDE_OPUS_4_8_VERSION} or newer to access it.`;} function formatClaudeOpus47UpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; return `Claude Code ${versionLabel} is too old for Claude Opus 4.7. Upgrade to v${MINIMUM_CLAUDE_OPUS_4_7_VERSION} or newer to access it.`;} export function getClaudeModelCapabilities(model: string | null | undefined): ModelCapabilities { const slug = model?.trim(); return ( BUILT_IN_MODELS.find((candidate) => candidate.slug === slug)?.capabilities ?? DEFAULT_CLAUDE_MODEL_CAPABILITIES );} export function resolveClaudeEffort( caps: ModelCapabilities, raw: string | null | undefined,): string | undefined { const descriptors = getProviderOptionDescriptors({ caps, ...(raw ? { selections: [{ id: "effort", value: raw }] } : {}), }); const effortDescriptor = descriptors.find((descriptor) => descriptor.id === "effort"); const value = getProviderOptionCurrentValue(effortDescriptor); return typeof value === "string" ? value : undefined;} /** * Normalize a resolved Claude effort value into one suitable for the Claude * CLI's `--effort` flag. * * Mirrors the mapping used when invoking the Claude Agent SDK * ({@link getEffectiveClaudeAgentEffort} in ClaudeAdapter): `ultracode` is a * Claude Code setting that pairs with `xhigh`, `ultrathink` is filtered out * because it is a prompt-prefix mode, and older model compatibility mappings * are preserved for current Claude Code behavior. */export function normalizeClaudeCliEffort( effort: string | null | undefined, model: string | null | undefined,): string | undefined { if (!effort || effort === "ultrathink") { return undefined; } if (effort === "ultracode") { return "xhigh"; } if ( effort === "xhigh" && model !== "claude-fable-5" && model !== "claude-opus-5" && model !== "claude-opus-4-8" && model !== "claude-sonnet-5" ) { return "max"; } if (effort === "max" && model === "claude-sonnet-4-6") { return "high"; } return effort;} export function isClaudeUltracodeEffort(effort: string | null | undefined): boolean { return effort === "ultracode";} export function resolveClaudeContextWindow( modelSelection: ModelSelection | undefined,): string | undefined { const caps = getClaudeModelCapabilities(modelSelection?.model); const raw = getModelSelectionStringOptionValue(modelSelection, "contextWindow"); const descriptors = getProviderOptionDescriptors({ caps, ...(raw ? { selections: [{ id: "contextWindow", value: raw }] } : {}), }); const descriptor = descriptors.find((candidate) => candidate.id === "contextWindow"); const value = getProviderOptionCurrentValue(descriptor); return typeof value === "string" ? value : undefined;} export function resolveClaudeApiModelId(modelSelection: ModelSelection): string { switch (resolveClaudeContextWindow(modelSelection)) { case "1m": return `${modelSelection.model}[1m]`; default: return modelSelection.model; }} function toTitleCaseWords(value: string): string { const parts: Array<string> = []; for (const part of value.split(/[\s_-]+/g)) { if (part.length > 0) { parts.push(part[0]!.toUpperCase() + part.slice(1).toLowerCase()); } } return parts.join(" ");} function claudeSubscriptionLabel(subscriptionType: string | undefined): string | undefined { const normalized = subscriptionType?.toLowerCase().replace(/[\s_-]+/g, ""); if (!normalized) return undefined; switch (normalized) { case "claudemaxsubscription": return "Max"; case "claudemax5xsubscription": return "Max 5x"; case "claudemax20xsubscription": return "Max 20x"; case "claudeenterprisesubscription": return "Enterprise"; case "claudeteamsubscription": return "Team"; case "claudeprosubscription": return "Pro"; case "claudefreesubscription": return "Free"; case "max": case "maxplan": return "Max"; case "max5": return "Max 5x"; case "max20": return "Max 20x"; case "enterprise": return "Enterprise"; case "team": return "Team";Lines 1–500 of 1005. Load more
import { type ClaudeSettings, type ModelCapabilities, type ModelSelection, type ServerProviderModel, type ServerProviderSlashCommand, } from "@t3tools/contracts"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Option from "effect/Option"; import * as Path from "effect/Path"; import * as Result from "effect/Result"; import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; import { createModelCapabilities, getModelSelectionStringOptionValue, getProviderOptionCurrentValue, getProviderOptionDescriptors, } from "@t3tools/shared/model"; import { resolveSpawnCommand } from "@t3tools/shared/shell"; import { compareSemverVersions } from "@t3tools/shared/semver"; import { query as claudeQuery, type Options as ClaudeQueryOptions, type SlashCommand as ClaudeSlashCommand, type SDKUserMessage, type SettingSource, } from "@anthropic-ai/claude-agent-sdk"; import { buildBooleanOptionDescriptor, buildSelectOptionDescriptor, buildServerProvider, DEFAULT_TIMEOUT_MS, isCommandMissingCause, parseGenericCliVersion, providerModelsFromSettings, spawnAndCollect, type ServerProviderDraft, } from "../providerSnapshot.ts"; import { resolveClaudeSdkExecutablePath } from "../Drivers/ClaudeExecutable.ts"; import { makeClaudeEnvironment } from "../Drivers/ClaudeHome.ts"; import { discoverClaudeSkills } from "../Drivers/ClaudeSkills.ts"; const DEFAULT_CLAUDE_MODEL_CAPABILITIES: ModelCapabilities = createModelCapabilities({ optionDescriptors: [], }); const CLAUDE_PRESENTATION = { displayName: "Claude", showInteractionModeToggle: true, } as const; const MINIMUM_CLAUDE_OPUS_5_VERSION = "2.1.219"; const MINIMUM_CLAUDE_FABLE_5_VERSION = "2.1.169"; const MINIMUM_CLAUDE_OPUS_4_8_VERSION = "2.1.154"; const MINIMUM_CLAUDE_OPUS_4_7_VERSION = "2.1.111"; const CURRENT_CLAUDE_MODELS = new Set(["claude-fable-5", "claude-opus-5", "claude-sonnet-5"]); export function isLegacyClaudeModel(model: string): boolean { return !CURRENT_CLAUDE_MODELS.has(model); } const CLAUDE_MODEL_CATALOG: ReadonlyArray<ServerProviderModel> = [ { slug: "claude-fable-5", name: "Claude Fable 5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "xhigh", label: "Extra High" }, { value: "max", label: "Max" }, { value: "ultracode", label: "Ultracode" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", options: [ { value: "200k", label: "200k" }, { value: "1m", label: "1M", isDefault: true }, ], }), ], }), }, { slug: "claude-opus-5", name: "Claude Opus 5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "xhigh", label: "Extra High" }, { value: "max", label: "Max" }, { value: "ultracode", label: "Ultracode" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", // Claude Code selects the 1M variant explicitly (`claude-opus-5[1m]`). options: [ { value: "200k", label: "200k" }, { value: "1m", label: "1M", isDefault: true }, ], }), ], }), }, { slug: "claude-opus-4-8", name: "Claude Opus 4.8", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "xhigh", label: "Extra High" }, { value: "max", label: "Max" }, { value: "ultracode", label: "Ultracode" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), ], }), }, { slug: "claude-opus-4-7", name: "Claude Opus 4.7", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High" }, { value: "xhigh", label: "Extra High", isDefault: true }, { value: "max", label: "Max" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), ], }), }, { slug: "claude-opus-4-6", name: "Claude Opus 4.6", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "max", label: "Max" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", options: [ { value: "200k", label: "200k" }, { value: "1m", label: "1M", isDefault: true }, ], }), ], }), }, { slug: "claude-opus-4-5", name: "Claude Opus 4.5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "max", label: "Max" }, ], }), buildBooleanOptionDescriptor({ id: "fastMode", label: "Fast Mode", }), ], }), }, { slug: "claude-sonnet-5", name: "Claude Sonnet 5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "xhigh", label: "Extra High" }, { value: "max", label: "Max" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", // Sonnet is 200k-default in Claude Code (1M is opt-in there too). options: [ { value: "200k", label: "200k", isDefault: true }, { value: "1m", label: "1M" }, ], }), ], }), }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildSelectOptionDescriptor({ id: "effort", label: "Reasoning", options: [ { value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "max", label: "Max" }, { value: "ultrathink", label: "Ultrathink" }, ], promptInjectedValues: ["ultrathink"], }), buildSelectOptionDescriptor({ id: "contextWindow", label: "Context Window", // Sonnet is 200k-default in Claude Code (1M is opt-in there too). options: [ { value: "200k", label: "200k", isDefault: true }, { value: "1m", label: "1M" }, ], }), ], }), }, { slug: "claude-haiku-4-5", name: "Claude Haiku 4.5", isCustom: false, capabilities: createModelCapabilities({ optionDescriptors: [ buildBooleanOptionDescriptor({ id: "thinking", label: "Thinking", }), ], }), }, ]; const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = CLAUDE_MODEL_CATALOG.map((model) => isLegacyClaudeModel(model.slug) ? { ...model, isLegacy: true } : model, ); function supportsClaudeOpus5(version: string | null | undefined): boolean { return version ? compareSemverVersions(version, MINIMUM_CLAUDE_OPUS_5_VERSION) >= 0 : false; } function supportsClaudeFable5(version: string | null | undefined): boolean { return version ? compareSemverVersions(version, MINIMUM_CLAUDE_FABLE_5_VERSION) >= 0 : false; } function supportsClaudeOpus48(version: string | null | undefined): boolean { return version ? compareSemverVersions(version, MINIMUM_CLAUDE_OPUS_4_8_VERSION) >= 0 : false; } function supportsClaudeOpus47(version: string | null | undefined): boolean { return version ? compareSemverVersions(version, MINIMUM_CLAUDE_OPUS_4_7_VERSION) >= 0 : false; } function getBuiltInClaudeModelsForVersion( version: string | null | undefined, ): ReadonlyArray<ServerProviderModel> { return BUILT_IN_MODELS.filter((model) => { if (model.slug === "claude-opus-5") { return supportsClaudeOpus5(version); } if (model.slug === "claude-fable-5") { return supportsClaudeFable5(version); } if (model.slug === "claude-opus-4-8") { return supportsClaudeOpus48(version); } if (model.slug === "claude-opus-4-7") { return supportsClaudeOpus47(version); } return true; }); } function formatClaudeOpus5UpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; return `Claude Code ${versionLabel} is too old for Claude Opus 5. Upgrade to v${MINIMUM_CLAUDE_OPUS_5_VERSION} or newer to access it.`; } function formatClaudeFable5UpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; return `Claude Code ${versionLabel} is too old for Claude Fable 5. Upgrade to v${MINIMUM_CLAUDE_FABLE_5_VERSION} or newer to access it.`; } function formatClaudeOpus48UpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; return `Claude Code ${versionLabel} is too old for Claude Opus 4.8. Upgrade to v${MINIMUM_CLAUDE_OPUS_4_8_VERSION} or newer to access it.`; } function formatClaudeOpus47UpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; return `Claude Code ${versionLabel} is too old for Claude Opus 4.7. Upgrade to v${MINIMUM_CLAUDE_OPUS_4_7_VERSION} or newer to access it.`; } export function getClaudeModelCapabilities(model: string | null | undefined): ModelCapabilities { const slug = model?.trim(); return ( BUILT_IN_MODELS.find((candidate) => candidate.slug === slug)?.capabilities ?? DEFAULT_CLAUDE_MODEL_CAPABILITIES ); } export function resolveClaudeEffort( caps: ModelCapabilities, raw: string | null | undefined, ): string | undefined { const descriptors = getProviderOptionDescriptors({ caps, ...(raw ? { selections: [{ id: "effort", value: raw }] } : {}), }); const effortDescriptor = descriptors.find((descriptor) => descriptor.id === "effort"); const value = getProviderOptionCurrentValue(effortDescriptor); return typeof value === "string" ? value : undefined; } /** * Normalize a resolved Claude effort value into one suitable for the Claude * CLI's `--effort` flag. * * Mirrors the mapping used when invoking the Claude Agent SDK * ({@link getEffectiveClaudeAgentEffort} in ClaudeAdapter): `ultracode` is a * Claude Code setting that pairs with `xhigh`, `ultrathink` is filtered out * because it is a prompt-prefix mode, and older model compatibility mappings * are preserved for current Claude Code behavior. */ export function normalizeClaudeCliEffort( effort: string | null | undefined, model: string | null | undefined, ): string | undefined { if (!effort || effort === "ultrathink") { return undefined; } if (effort === "ultracode") { return "xhigh"; } if ( effort === "xhigh" && model !== "claude-fable-5" && model !== "claude-opus-5" && model !== "claude-opus-4-8" && model !== "claude-sonnet-5" ) { return "max"; } if (effort === "max" && model === "claude-sonnet-4-6") { return "high"; } return effort; } export function isClaudeUltracodeEffort(effort: string | null | undefined): boolean { return effort === "ultracode"; } export function resolveClaudeContextWindow( modelSelection: ModelSelection | undefined, ): string | undefined { const caps = getClaudeModelCapabilities(modelSelection?.model); const raw = getModelSelectionStringOptionValue(modelSelection, "contextWindow"); const descriptors = getProviderOptionDescriptors({ caps, ...(raw ? { selections: [{ id: "contextWindow", value: raw }] } : {}), }); const descriptor = descriptors.find((candidate) => candidate.id === "contextWindow"); const value = getProviderOptionCurrentValue(descriptor); return typeof value === "string" ? value : undefined; } export function resolveClaudeApiModelId(modelSelection: ModelSelection): string { switch (resolveClaudeContextWindow(modelSelection)) { case "1m": return `${modelSelection.model}[1m]`; default: return modelSelection.model; } } function toTitleCaseWords(value: string): string { const parts: Array<string> = []; for (const part of value.split(/[\s_-]+/g)) { if (part.length > 0) { parts.push(part[0]!.toUpperCase() + part.slice(1).toLowerCase()); } } return parts.join(" "); } function claudeSubscriptionLabel(subscriptionType: string | undefined): string | undefined { const normalized = subscriptionType?.toLowerCase().replace(/[\s_-]+/g, ""); if (!normalized) return undefined; switch (normalized) { case "claudemaxsubscription": return "Max"; case "claudemax5xsubscription": return "Max 5x"; case "claudemax20xsubscription": return "Max 20x"; case "claudeenterprisesubscription": return "Enterprise"; case "claudeteamsubscription": return "Team"; case "claudeprosubscription": return "Pro"; case "claudefreesubscription": return "Free"; case "max": case "maxplan": return "Max"; case "max5": return "Max 5x"; case "max20": return "Max 20x"; case "enterprise": return "Enterprise"; case "team": return "Team";