The local/worktree choice was unstored component state and reset on every remount of the New Workspace screen (e.g. after creating a workspace). Persist it in the create-form preferences (FormPreferences.isolation). Also rename the app-layer "backing" to "isolation" to match its UI label. Isolation is the create-time intent; it stays distinct from workspaceKind, the git-derived persisted property, and the wire's source.kind.
149 lines
4.3 KiB
TypeScript
149 lines
4.3 KiB
TypeScript
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()).optional(),
|
|
featureValues: z.record(z.unknown()).optional(),
|
|
});
|
|
|
|
const formPreferencesSchema = z.object({
|
|
provider: z.string().optional(),
|
|
providerPreferences: z.record(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<typeof providerPreferencesSchema>;
|
|
export type FormPreferences = z.infer<typeof formPreferencesSchema>;
|
|
|
|
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;
|
|
}
|
|
|
|
export function mergeProviderPreferences(args: {
|
|
preferences: FormPreferences;
|
|
provider: AgentProvider;
|
|
updates: Partial<ProviderPreferences>;
|
|
}): FormPreferences {
|
|
const { preferences, provider, updates } = args;
|
|
const existingProviderPreferences = preferences.providerPreferences ?? {};
|
|
const existing = existingProviderPreferences[provider] ?? {};
|
|
const nextThinkingByModel =
|
|
updates.thinkingByModel === undefined
|
|
? existing.thinkingByModel
|
|
: {
|
|
...existing.thinkingByModel,
|
|
...updates.thinkingByModel,
|
|
};
|
|
const nextFeatureValues =
|
|
updates.featureValues === undefined
|
|
? existing.featureValues
|
|
: {
|
|
...existing.featureValues,
|
|
...updates.featureValues,
|
|
};
|
|
|
|
return {
|
|
...preferences,
|
|
provider,
|
|
providerPreferences: {
|
|
...existingProviderPreferences,
|
|
[provider]: {
|
|
...existing,
|
|
...updates,
|
|
...(nextThinkingByModel ? { thinkingByModel: nextThinkingByModel } : {}),
|
|
...(nextFeatureValues ? { featureValues: nextFeatureValues } : {}),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
export function mergeCreateAgentSelectionPreferences(args: {
|
|
preferences: FormPreferences;
|
|
provider: AgentProvider | null;
|
|
modelId?: string | null;
|
|
modeId?: string | null;
|
|
thinkingOptionId?: string | null;
|
|
featureValues?: Record<string, unknown>;
|
|
}): 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],
|
|
};
|
|
}
|