181 lines · 5.0 KB · TypeScript
RawDownload
import {  DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER,  type ModelSelection,  type ProviderKind,} from "@t3tools/contracts";import {  getDefaultModel,  getModelOptions,  normalizeModelSlug,  resolveSelectableModel,} from "@t3tools/shared/model";import { getComposerProviderState } from "./components/chat/composerProviderRegistry";import { UnifiedSettings } from "./appSettings"; const MAX_CUSTOM_MODEL_COUNT = 32;export const MAX_CUSTOM_MODEL_LENGTH = 256; export type ProviderCustomModelConfig = {  provider: ProviderKind;  title: string;  description: string;  placeholder: string;  example: string;}; export interface AppModelOption {  slug: string;  name: string;  isCustom: boolean;} const PROVIDER_CUSTOM_MODEL_CONFIG: Record<ProviderKind, ProviderCustomModelConfig> = {  codex: {    provider: "codex",    title: "Codex",    description: "Save additional Codex model slugs for the picker and `/model` command.",    placeholder: "your-codex-model-slug",    example: "gpt-6.7-codex-ultra-preview",  },  claudeAgent: {    provider: "claudeAgent",    title: "Claude",    description: "Save additional Claude model slugs for the picker and `/model` command.",    placeholder: "your-claude-model-slug",    example: "claude-sonnet-5-0",  },}; const BUILT_IN_MODEL_SLUGS_BY_PROVIDER: Record<ProviderKind, ReadonlySet<string>> = {  codex: new Set(getModelOptions("codex").map((option) => option.slug)),  claudeAgent: new Set(getModelOptions("claudeAgent").map((option) => option.slug)),}; export const MODEL_PROVIDER_SETTINGS = Object.values(PROVIDER_CUSTOM_MODEL_CONFIG); export function normalizeCustomModelSlugs(  models: Iterable<string | null | undefined>,  provider: ProviderKind = "codex",): string[] {  const normalizedModels: string[] = [];  const seen = new Set<string>();  const builtInModelSlugs = BUILT_IN_MODEL_SLUGS_BY_PROVIDER[provider];   for (const candidate of models) {    const normalized = normalizeModelSlug(candidate, provider);    if (      !normalized ||      normalized.length > MAX_CUSTOM_MODEL_LENGTH ||      builtInModelSlugs.has(normalized) ||      seen.has(normalized)    ) {      continue;    }     seen.add(normalized);    normalizedModels.push(normalized);    if (normalizedModels.length >= MAX_CUSTOM_MODEL_COUNT) {      break;    }  }   return normalizedModels;} export function getAppModelOptions(  settings: UnifiedSettings,  provider: ProviderKind,  selectedModel?: string | null,): AppModelOption[] {  const options: AppModelOption[] = getModelOptions(provider).map(({ slug, name }) => ({    slug,    name,    isCustom: false,  }));  const seen = new Set(options.map((option) => option.slug));  const trimmedSelectedModel = selectedModel?.trim().toLowerCase();   const customModels = settings.providers[provider].customModels;  for (const slug of normalizeCustomModelSlugs(customModels, provider)) {    if (seen.has(slug)) {      continue;    }     seen.add(slug);    options.push({      slug,      name: slug,      isCustom: true,    });  }   const normalizedSelectedModel = normalizeModelSlug(selectedModel, provider);  const selectedModelMatchesExistingName =    typeof trimmedSelectedModel === "string" &&    options.some((option) => option.name.toLowerCase() === trimmedSelectedModel);  if (    normalizedSelectedModel &&    !seen.has(normalizedSelectedModel) &&    !selectedModelMatchesExistingName  ) {    options.push({      slug: normalizedSelectedModel,      name: normalizedSelectedModel,      isCustom: true,    });  }   return options;} export function resolveAppModelSelection(  provider: ProviderKind,  settings: UnifiedSettings,   selectedModel: string | null | undefined,): string {  const options = getAppModelOptions(settings, provider, selectedModel);  return resolveSelectableModel(provider, selectedModel, options) ?? getDefaultModel(provider);} export function getCustomModelOptionsByProvider(  settings: UnifiedSettings,  selectedProvider?: ProviderKind | null,  selectedModel?: string | null,): Record<ProviderKind, ReadonlyArray<{ slug: string; name: string }>> {  return {    codex: getAppModelOptions(      settings,      "codex",      selectedProvider === "codex" ? selectedModel : undefined,    ),    claudeAgent: getAppModelOptions(      settings,      "claudeAgent",      selectedProvider === "claudeAgent" ? selectedModel : undefined,    ),  };} export function resolveAppModelSelectionState(settings: UnifiedSettings): ModelSelection {  const selection = settings.textGenerationModelSelection ?? {    provider: "codex" as const,    model: DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER.codex,  };   const model = resolveAppModelSelection(selection.provider, settings, selection.model);  const { modelOptionsForDispatch } = getComposerProviderState({    provider: selection.provider,    model,    prompt: "",    modelOptions: {      [selection.provider]: selection.options,    },  });   return {    provider: selection.provider,    model,    ...(modelOptionsForDispatch ? { options: modelOptionsForDispatch } : {}),  };}