import { getProviderScopedTeamModelLabel, getRuntimeAwareProviderScopedTeamModelLabel, getRuntimeAwareTeamModelBadgeLabel, getRuntimeAwareTeamModelUiDisabledReason, getTeamModelSourceBadgeLabel, getTeamProviderLabel, getTeamProviderModelOptions, getVisibleTeamProviderModels, isSupportedAnthropicTeamModel, normalizeTeamModelForUi as normalizeCatalogTeamModelForUi, sortTeamProviderModels, type TeamProviderModelOption, } from './teamModelCatalog'; import { extractProviderScopedBaseModel } from './teamModelContext'; import type { CliProviderId, CliProviderModelAvailability, CliProviderModelAvailabilityStatus, CliProviderStatus, TeamProviderId, } from '@shared/types'; export { GPT_5_1_CODEX_MAX_CHATGPT_UI_DISABLED_REASON, GPT_5_1_CODEX_MINI_UI_DISABLED_MODEL, GPT_5_1_CODEX_MINI_UI_DISABLED_REASON, GPT_5_2_CODEX_UI_DISABLED_MODEL, GPT_5_2_CODEX_UI_DISABLED_REASON, GPT_5_3_CODEX_SPARK_UI_DISABLED_MODEL, GPT_5_3_CODEX_SPARK_UI_DISABLED_REASON, TEAM_MODEL_UI_DISABLED_BADGE_LABEL, } from './teamModelCatalog'; type SupportedProviderId = CliProviderId | TeamProviderId; export const OPENCODE_OPENAI_AUTH_UNAVAILABLE_REASON = 'OpenCode OpenAI provider authentication failed. Reconnect OpenAI in provider settings, then refresh runtime status.'; export type TeamModelRuntimeProviderStatus = Pick< CliProviderStatus, | 'providerId' | 'models' | 'modelCatalog' | 'modelAvailability' | 'modelVerificationState' | 'runtimeCapabilities' | 'authMethod' | 'backend' | 'authenticated' | 'supported' | 'detailMessage' | 'availableBackends' | 'externalRuntimeDiagnostics' > & Partial>; export type TeamRuntimeModelOption = TeamProviderModelOption & { availabilityStatus?: CliProviderModelAvailabilityStatus | null; availabilityReason?: string | null; }; export interface TeamProviderModelVerificationCounts { checkedCount: number; totalCount: number; verifying: boolean; } export function getOpenCodeOpenAiRouteAuthUnavailableReason( providerId: SupportedProviderId | undefined, model: string | undefined, providerStatus?: TeamModelRuntimeProviderStatus | null ): string | null { if ( providerId !== 'opencode' || !model?.trim().toLowerCase().startsWith('openai/') || !providerStatus ) { return null; } const openAiBackends = (providerStatus.availableBackends ?? []).filter((backend) => [backend.id, backend.label, backend.description].some((value) => /\bopenai\b/i.test(value)) ); const backendRequiresAuth = openAiBackends.some( (backend) => backend.state === 'authentication-required' || (!backend.available && [backend.statusMessage, backend.detailMessage].some((value) => /auth|token|api key|401|403/i.test(value ?? '') )) ); if (backendRequiresAuth) { return OPENCODE_OPENAI_AUTH_UNAVAILABLE_REASON; } const diagnosticText = [ providerStatus.statusMessage, providerStatus.detailMessage, ...openAiBackends.flatMap((backend) => [backend.statusMessage, backend.detailMessage]), ...(providerStatus.externalRuntimeDiagnostics ?? []) .filter((diagnostic) => /\bopenai\b/i.test(diagnostic.label)) .flatMap((diagnostic) => [diagnostic.statusMessage, diagnostic.detailMessage]), ] .map((value) => value?.trim() ?? '') .filter(Boolean) .join('\n'); if ( /\bopenai\b/i.test(diagnosticText) && /token refresh failed|token.*invalid|invalid.*token|not[_\s-]?authenticated|not authenticated|unauthorized|forbidden|\b401\b|\b403\b|invalid api key|api key.*invalid|authentication required/i.test( diagnosticText ) ) { return OPENCODE_OPENAI_AUTH_UNAVAILABLE_REASON; } return null; } export function getTeamModelUiDisabledReason( providerId: SupportedProviderId | undefined, model: string | undefined, providerStatus?: TeamModelRuntimeProviderStatus | null ): string | null { return getRuntimeAwareTeamModelUiDisabledReason(providerId, model, providerStatus); } export function isTeamModelUiDisabled( providerId: SupportedProviderId | undefined, model: string | undefined, providerStatus?: TeamModelRuntimeProviderStatus | null ): boolean { return getTeamModelUiDisabledReason(providerId, model, providerStatus) !== null; } export function isTeamProviderModelVerificationPending( providerId: SupportedProviderId | undefined, providerStatus?: TeamModelRuntimeProviderStatus | null ): boolean { if (!providerId || providerId === 'anthropic' || !providerStatus) { return false; } if (providerStatus.modelVerificationState === 'verifying') { return true; } const hasRuntimeModelTruth = providerStatus.models.length > 0 || (providerStatus.modelCatalog?.models.length ?? 0) > 0 || (providerStatus.modelAvailability?.length ?? 0) > 0; if (!hasRuntimeModelTruth) { if ( providerId === 'codex' && providerStatus.backend?.kind === 'codex-native' && providerStatus.supported ) { return true; } if ( providerId === 'opencode' && providerStatus.backend?.kind === 'opencode-cli' && providerStatus.supported ) { return true; } } if (providerStatus.verificationState !== 'unknown') { return false; } if (hasRuntimeModelTruth) { return false; } const statusMessage = providerStatus.statusMessage?.trim().toLowerCase() ?? ''; return statusMessage.length === 0 || statusMessage === 'checking...'; } function getFallbackTeamProviderModels(providerId: SupportedProviderId): string[] { return getVisibleTeamProviderModels( providerId, getTeamProviderModelOptions(providerId) .map((option) => option.value) .filter((value) => value.trim().length > 0) ); } function getFallbackTeamProviderModelOptions( providerId: SupportedProviderId, providerStatus?: TeamModelRuntimeProviderStatus | null ): TeamRuntimeModelOption[] { return getTeamProviderModelOptions(providerId).map((option) => ({ ...option, label: option.value === '' ? option.label : (getRuntimeAwareProviderScopedTeamModelLabel(providerId, option.value, providerStatus) ?? option.value), badgeLabel: option.value === '' ? option.badgeLabel : (getRuntimeAwareTeamModelBadgeLabel(providerId, option.value, providerStatus) ?? option.badgeLabel), })); } function hasAnthropicRuntimeCatalog( providerStatus?: TeamModelRuntimeProviderStatus | null ): boolean { return providerStatus?.modelCatalog?.providerId === 'anthropic'; } function getAnthropicCatalogModel( model: string, providerStatus?: TeamModelRuntimeProviderStatus | null ): NonNullable['models'][number] | null { const catalog = hasAnthropicRuntimeCatalog(providerStatus) ? providerStatus?.modelCatalog : null; if (!catalog) { return null; } return catalog.models.find((item) => item.launchModel === model || item.id === model) ?? null; } function getRuntimeCatalogModels( providerId: SupportedProviderId, providerStatus?: TeamModelRuntimeProviderStatus | null ): string[] | null { if (providerId === 'anthropic') { return null; } if (providerId !== 'codex' || providerStatus?.modelCatalog?.providerId !== 'codex') { return null; } const models = providerStatus.modelCatalog.models .filter((model) => !model.hidden) .map((model) => model.launchModel.trim()) .filter(Boolean); return models.length > 0 ? models : null; } function getRuntimeCatalogModelOption( providerId: SupportedProviderId, model: string, providerStatus?: TeamModelRuntimeProviderStatus | null ): TeamRuntimeModelOption | null { if (providerId !== 'codex' || providerStatus?.modelCatalog?.providerId !== 'codex') { return null; } const catalogModel = providerStatus.modelCatalog.models.find( (item) => item.launchModel === model || item.id === model ); if (!catalogModel) { return null; } return { value: catalogModel.launchModel, label: getProviderScopedTeamModelLabel(providerId, catalogModel.displayName) ?? catalogModel.displayName, badgeLabel: catalogModel.badgeLabel ?? (getTeamProviderModelOptions(providerId).some((option) => option.value === model) ? undefined : 'New'), availabilityStatus: getRuntimeModelAvailability( providerId, catalogModel.launchModel, providerStatus ), availabilityReason: getRuntimeModelAvailabilityReason(catalogModel.launchModel, providerStatus), }; } function getRuntimeSelectorModels( providerId: SupportedProviderId, providerStatus?: TeamModelRuntimeProviderStatus | null ): string[] { if (!providerStatus) { return []; } const catalogModels = getRuntimeCatalogModels(providerId, providerStatus); if (catalogModels) { return getVisibleTeamProviderModels(providerId, catalogModels, providerStatus); } return sortTeamProviderModels(providerId, providerStatus.models, providerStatus); } function getVisibleRuntimeModels( providerId: SupportedProviderId, providerStatus?: TeamModelRuntimeProviderStatus | null ): string[] { return getRuntimeSelectorModels(providerId, providerStatus).filter( (model) => getTeamModelUiDisabledReason(providerId, model, providerStatus) == null ); } function withSupplementalDisabledRuntimeModels( providerId: SupportedProviderId, models: readonly string[], providerStatus?: TeamModelRuntimeProviderStatus | null ): string[] { if (providerId !== 'codex') { return [...models]; } const modelSet = new Set(models); const supplementalDisabledModels = getTeamProviderModelOptions(providerId) .map((option) => option.value.trim()) .filter( (model) => model.length > 0 && !modelSet.has(model) && getTeamModelUiDisabledReason(providerId, model, providerStatus) !== null ); return sortTeamProviderModels( providerId, [...models, ...supplementalDisabledModels], providerStatus ); } function getModelAvailabilityMap( providerStatus?: TeamModelRuntimeProviderStatus | null ): Map { return new Map( (providerStatus?.modelAvailability ?? []).map((item) => [item.modelId.trim(), item]) ); } function getRuntimeModelAvailabilityFromLookup( model: string, visibleModelSet: ReadonlySet, modelAvailabilityById: ReadonlyMap ): CliProviderModelAvailabilityStatus | null { if (!visibleModelSet.has(model)) { return null; } const runtimeAvailability = modelAvailabilityById.get(model)?.status ?? null; if (runtimeAvailability === 'unavailable') { return 'unavailable'; } return 'available'; } function getRuntimeModelAvailability( providerId: SupportedProviderId, model: string, providerStatus?: TeamModelRuntimeProviderStatus | null ): CliProviderModelAvailabilityStatus | null { if (providerId === 'anthropic') { if (!providerStatus || !hasAnthropicRuntimeCatalog(providerStatus)) { return isSupportedAnthropicTeamModel(model) ? 'available' : null; } return getAnthropicCatalogModel(model, providerStatus) ? 'available' : null; } if (!providerStatus) { return null; } const visibleModels = getVisibleRuntimeModels(providerId, providerStatus); if (!visibleModels.includes(model)) { return null; } const runtimeAvailability = getModelAvailabilityMap(providerStatus).get(model)?.status ?? null; if (runtimeAvailability === 'unavailable') { return 'unavailable'; } return 'available'; } function getRuntimeModelAvailabilityReason( model: string, providerStatus?: TeamModelRuntimeProviderStatus | null ): string | null { return getModelAvailabilityMap(providerStatus).get(model)?.reason ?? null; } export function getTeamProviderModelVerificationCounts( providerId: SupportedProviderId, providerStatus?: TeamModelRuntimeProviderStatus | null ): TeamProviderModelVerificationCounts { if (providerId === 'anthropic') { const visibleAnthropicModels = getFallbackTeamProviderModels(providerId); return { checkedCount: visibleAnthropicModels.length, totalCount: visibleAnthropicModels.length, verifying: false, }; } const totalCount = getRuntimeSelectorModels(providerId, providerStatus).length; return { checkedCount: totalCount, totalCount, verifying: false, }; } export function getAvailableTeamProviderModels( providerId: SupportedProviderId, providerStatus?: TeamModelRuntimeProviderStatus | null ): string[] { if (providerId === 'anthropic') { return getFallbackTeamProviderModels(providerId).filter( (model) => getRuntimeModelAvailability(providerId, model, providerStatus) === 'available' ); } if (!providerStatus) { return []; } const visibleModels = getVisibleRuntimeModels(providerId, providerStatus); const modelAvailabilityById = getModelAvailabilityMap(providerStatus); return visibleModels.filter( (model) => modelAvailabilityById.get(model)?.status !== 'unavailable' ); } export function getAvailableTeamProviderModelOptions( providerId: SupportedProviderId, providerStatus?: TeamModelRuntimeProviderStatus | null ): TeamRuntimeModelOption[] { if (providerId === 'anthropic') { return getFallbackTeamProviderModelOptions(providerId, providerStatus).map((option) => ({ ...option, availabilityStatus: option.value.trim().length > 0 ? getRuntimeModelAvailability(providerId, option.value, providerStatus) : undefined, availabilityReason: option.value.trim().length > 0 ? getRuntimeModelAvailabilityReason(option.value, providerStatus) : undefined, })); } if (!providerStatus) { return [{ value: '', label: 'Default', badgeLabel: 'Default' }]; } if (isTeamProviderModelVerificationPending(providerId, providerStatus)) { return getFallbackTeamProviderModelOptions(providerId, providerStatus); } const visibleModels = withSupplementalDisabledRuntimeModels( providerId, getRuntimeSelectorModels(providerId, providerStatus), providerStatus ); const runtimeVisibleModelSet = new Set( visibleModels.filter( (model) => getTeamModelUiDisabledReason(providerId, model, providerStatus) == null ) ); const modelAvailabilityById = getModelAvailabilityMap(providerStatus); const getPrecomputedAvailability = (model: string): CliProviderModelAvailabilityStatus | null => getRuntimeModelAvailabilityFromLookup(model, runtimeVisibleModelSet, modelAvailabilityById); const getPrecomputedAvailabilityReason = (model: string): string | null => modelAvailabilityById.get(model)?.reason ?? null; return [ { value: '', label: 'Default', badgeLabel: 'Default' }, ...visibleModels.map((model) => { const catalogOption = getRuntimeCatalogModelOption(providerId, model, providerStatus); if (catalogOption) { return { ...catalogOption, availabilityStatus: getPrecomputedAvailability(model), availabilityReason: getPrecomputedAvailabilityReason(model), }; } return { value: model, label: getProviderScopedTeamModelLabel(providerId, model) ?? model, badgeLabel: providerId === 'opencode' ? (getTeamModelSourceBadgeLabel(providerId, model) ?? undefined) : undefined, availabilityStatus: getPrecomputedAvailability(model), availabilityReason: getPrecomputedAvailabilityReason(model), }; }), ]; } export function isTeamModelAvailableForUi( providerId: SupportedProviderId | undefined, model: string | undefined, providerStatus?: TeamModelRuntimeProviderStatus | null ): boolean { const trimmed = model?.trim(); if (!providerId || !trimmed) { return true; } if (getTeamModelUiDisabledReason(providerId, trimmed, providerStatus)) { return false; } if (providerId === 'anthropic') { if (!isSupportedAnthropicTeamModel(trimmed)) { return false; } return getRuntimeModelAvailability(providerId, trimmed, providerStatus) === 'available'; } if (isTeamProviderModelVerificationPending(providerId, providerStatus)) { return true; } return getRuntimeModelAvailability(providerId, trimmed, providerStatus) === 'available'; } export function normalizeExplicitTeamModelForUi( providerId: SupportedProviderId | undefined, model: string | undefined ): string { const normalized = extractProviderScopedBaseModel(model, providerId) ?? ''; return normalizeCatalogTeamModelForUi(providerId, normalized).trim(); } export function normalizeTeamModelForUi( providerId: SupportedProviderId | undefined, model: string | undefined, providerStatus?: TeamModelRuntimeProviderStatus | null ): string { const normalized = normalizeCatalogTeamModelForUi(providerId, model); const trimmed = normalized.trim(); if (!providerId || !trimmed) { return normalized; } if (getTeamModelUiDisabledReason(providerId, trimmed, providerStatus)) { return ''; } if (providerId === 'anthropic') { return isTeamModelAvailableForUi(providerId, trimmed, providerStatus) ? normalized : ''; } if (!providerStatus) { return ''; } if (isTeamProviderModelVerificationPending(providerId, providerStatus)) { return normalized; } const visibleModels = getVisibleRuntimeModels(providerId, providerStatus); if (!visibleModels.includes(trimmed)) { return ''; } const availability = getRuntimeModelAvailability(providerId, trimmed, providerStatus); return availability === 'available' ? normalized : ''; } export function getTeamModelSelectionError( providerId: SupportedProviderId | undefined, model: string | undefined, providerStatus?: TeamModelRuntimeProviderStatus | null ): string | null { const trimmed = model?.trim(); if (!providerId || !trimmed) { return null; } const disabledReason = getTeamModelUiDisabledReason(providerId, trimmed, providerStatus); if (disabledReason) { return `Model "${trimmed}" is disabled. ${disabledReason}`; } const dynamicUnavailableReason = getOpenCodeOpenAiRouteAuthUnavailableReason( providerId, trimmed, providerStatus ); if (dynamicUnavailableReason) { return `Model "${trimmed}" is not available for the current ${getTeamProviderLabel(providerId) ?? providerId} runtime. ${dynamicUnavailableReason}`; } if (providerId === 'anthropic') { return isTeamModelAvailableForUi(providerId, trimmed, providerStatus) ? null : `Model "${trimmed}" is not available for the current ${getTeamProviderLabel(providerId) ?? providerId} runtime. Pick one of the listed models or use Default.`; } if (!providerStatus) { return null; } if (isTeamProviderModelVerificationPending(providerId, providerStatus)) { return null; } const visibleModels = getVisibleRuntimeModels(providerId, providerStatus); if (!visibleModels.includes(trimmed)) { return `Model "${trimmed}" is not available for the current ${getTeamProviderLabel(providerId) ?? providerId} runtime. Pick one of the listed models or use Default.`; } const availability = getRuntimeModelAvailability(providerId, trimmed, providerStatus); if (availability !== 'available') { const reason = getRuntimeModelAvailabilityReason(trimmed, providerStatus); const reasonSuffix = reason ? ` ${reason}` : ''; return `Model "${trimmed}" is not available for the current ${getTeamProviderLabel(providerId) ?? providerId} runtime.${reasonSuffix} Pick one of the listed models or use Default.`; } return null; }