feat: add preset configurations with built-in and custom presets
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>
This commit is contained in:
116
src/lib/stores/presets.svelte.ts
Normal file
116
src/lib/stores/presets.svelte.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
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();
|
||||
Reference in New Issue
Block a user