Add preset store with three built-in presets (Strict mode, Research only, Full access) and localStorage persistence for custom presets. Integrate preset selector into ConfigSidebar with load, save, and delete actions. Built-in presets cannot be deleted. Closes #14 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
117 lines
2.8 KiB
TypeScript
117 lines
2.8 KiB
TypeScript
import { OverrideLevel } from '$lib/proto/llm_multiverse/v1/common_pb';
|
|
|
|
export interface PresetConfig {
|
|
overrideLevel: OverrideLevel;
|
|
disabledTools: string[];
|
|
grantedPermissions: string[];
|
|
}
|
|
|
|
export interface Preset {
|
|
name: string;
|
|
config: PresetConfig;
|
|
builtIn: boolean;
|
|
}
|
|
|
|
const STORAGE_KEY = 'llm-multiverse-presets';
|
|
|
|
const builtInPresets: Preset[] = [
|
|
{
|
|
name: 'Strict mode',
|
|
config: {
|
|
overrideLevel: OverrideLevel.NONE,
|
|
disabledTools: ['FS Write', 'Run Shell', 'Run Code', 'Package Install'],
|
|
grantedPermissions: []
|
|
},
|
|
builtIn: true
|
|
},
|
|
{
|
|
name: 'Research only',
|
|
config: {
|
|
overrideLevel: OverrideLevel.NONE,
|
|
disabledTools: ['Memory Write', 'FS Write', 'Run Code', 'Run Shell', 'Package Install'],
|
|
grantedPermissions: []
|
|
},
|
|
builtIn: true
|
|
},
|
|
{
|
|
name: 'Full access',
|
|
config: {
|
|
overrideLevel: OverrideLevel.ALL,
|
|
disabledTools: [],
|
|
grantedPermissions: []
|
|
},
|
|
builtIn: true
|
|
}
|
|
];
|
|
|
|
function loadCustomPresets(): Preset[] {
|
|
if (typeof localStorage === 'undefined') return [];
|
|
try {
|
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
if (!raw) return [];
|
|
const parsed: Preset[] = JSON.parse(raw);
|
|
return parsed.map((p) => ({ ...p, builtIn: false }));
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function saveCustomPresets(presets: Preset[]) {
|
|
if (typeof localStorage === 'undefined') return;
|
|
const custom = presets.filter((p) => !p.builtIn);
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(custom));
|
|
}
|
|
|
|
function createPresetStore() {
|
|
const customPresets = $state<Preset[]>(loadCustomPresets());
|
|
|
|
function getAllPresets(): Preset[] {
|
|
return [...builtInPresets, ...customPresets];
|
|
}
|
|
|
|
function savePreset(name: string, config: PresetConfig): Preset {
|
|
const trimmed = name.trim();
|
|
if (!trimmed) throw new Error('Preset name cannot be empty');
|
|
if (builtInPresets.some((p) => p.name === trimmed)) {
|
|
throw new Error('Cannot overwrite a built-in preset');
|
|
}
|
|
|
|
const existing = customPresets.findIndex((p) => p.name === trimmed);
|
|
const preset: Preset = { name: trimmed, config, builtIn: false };
|
|
|
|
if (existing >= 0) {
|
|
customPresets[existing] = preset;
|
|
} else {
|
|
customPresets.push(preset);
|
|
}
|
|
|
|
saveCustomPresets(customPresets);
|
|
return preset;
|
|
}
|
|
|
|
function loadPreset(name: string): PresetConfig | null {
|
|
const all = getAllPresets();
|
|
const preset = all.find((p) => p.name === name);
|
|
return preset?.config ?? null;
|
|
}
|
|
|
|
function deletePreset(name: string): boolean {
|
|
if (builtInPresets.some((p) => p.name === name)) return false;
|
|
const idx = customPresets.findIndex((p) => p.name === name);
|
|
if (idx < 0) return false;
|
|
|
|
customPresets.splice(idx, 1);
|
|
saveCustomPresets(customPresets);
|
|
return true;
|
|
}
|
|
|
|
return {
|
|
getAllPresets,
|
|
savePreset,
|
|
loadPreset,
|
|
deletePreset
|
|
};
|
|
}
|
|
|
|
export const presetStore = createPresetStore();
|