import { z } from "zod"; import type { AgentProvider } from "@getpaseo/protocol/agent-types"; export interface FavoriteModelPreference { provider: string; modelId: string; } export interface FavoriteModelRow { favoriteKey: string; provider: string; providerLabel: string; modelId: string; modelLabel: string; description?: string; } const providerPreferencesSchema = z.object({ model: z.string().optional(), mode: z.string().optional(), thinkingByModel: z.record(z.string(), z.string()).optional(), featureValues: z.record(z.string(), z.unknown()).optional(), }); const formPreferencesSchema = z.object({ provider: z.string().optional(), providerPreferences: z.record(z.string(), providerPreferencesSchema).optional(), favoriteModels: z .array( z.object({ provider: z.string(), modelId: z.string(), }), ) .optional(), isolation: z.enum(["local", "worktree"]).optional(), }); export type ProviderPreferences = z.infer; export type FormPreferences = z.infer; export const DEFAULT_FORM_PREFERENCES: FormPreferences = {}; export function parseFormPreferences(value: unknown): FormPreferences { const result = formPreferencesSchema.safeParse(value); return result.success ? result.data : DEFAULT_FORM_PREFERENCES; } function mergeDefinedRecord( existing: Record | undefined, updates: Record | undefined, ): Record | undefined { if (updates === undefined) { return existing; } return { ...existing, ...updates, }; } function applyProviderPreferenceUpdates( existing: ProviderPreferences, updates: Partial, ): ProviderPreferences { const next: ProviderPreferences = { ...existing }; const nextThinkingByModel = mergeDefinedRecord(existing.thinkingByModel, updates.thinkingByModel); const nextFeatureValues = mergeDefinedRecord(existing.featureValues, updates.featureValues); if (updates.model !== undefined) { next.model = updates.model; } if (updates.mode !== undefined) { next.mode = updates.mode; } if (nextThinkingByModel !== undefined) { next.thinkingByModel = nextThinkingByModel; } if (nextFeatureValues !== undefined) { next.featureValues = nextFeatureValues; } return next; } export function mergeProviderPreferences(args: { preferences: FormPreferences; provider: AgentProvider; updates: Partial; }): FormPreferences { const { preferences, provider, updates } = args; const existingProviderPreferences = preferences.providerPreferences ?? {}; const existing = existingProviderPreferences[provider] ?? {}; return { ...preferences, provider, providerPreferences: { ...existingProviderPreferences, [provider]: applyProviderPreferenceUpdates(existing, updates), }, }; } export function mergeCreateAgentSelectionPreferences(args: { preferences: FormPreferences; provider: AgentProvider | null; modelId?: string | null; modeId?: string | null; thinkingOptionId?: string | null; featureValues?: Record; }): FormPreferences { if (!args.provider) { return args.preferences; } const modelId = args.modelId?.trim() ?? ""; const modeId = args.modeId?.trim() ?? ""; const thinkingOptionId = args.thinkingOptionId?.trim() ?? ""; return mergeProviderPreferences({ preferences: args.preferences, provider: args.provider, updates: { model: modelId || undefined, mode: modeId || undefined, ...(modelId && thinkingOptionId ? { thinkingByModel: { [modelId]: thinkingOptionId } } : {}), ...(args.featureValues ? { featureValues: args.featureValues } : {}), }, }); } export function buildFavoriteModelKey(input: FavoriteModelPreference): string { return `${input.provider}:${input.modelId}`; } export function isFavoriteModel(args: { preferences: FormPreferences; provider: string; modelId: string; }): boolean { const favoriteKey = buildFavoriteModelKey({ provider: args.provider, modelId: args.modelId }); return (args.preferences.favoriteModels ?? []).some( (favorite) => buildFavoriteModelKey(favorite) === favoriteKey, ); } export function toggleFavoriteModel(args: { preferences: FormPreferences; provider: string; modelId: string; }): FormPreferences { const favorite = { provider: args.provider, modelId: args.modelId }; const favoriteKey = buildFavoriteModelKey(favorite); const existingFavorites = args.preferences.favoriteModels ?? []; const hasFavorite = existingFavorites.some( (entry) => buildFavoriteModelKey(entry) === favoriteKey, ); return { ...args.preferences, favoriteModels: hasFavorite ? existingFavorites.filter((entry) => buildFavoriteModelKey(entry) !== favoriteKey) : [...existingFavorites, favorite], }; }