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:
shahondin1624
2026-03-12 12:07:50 +01:00
parent a14a92a87d
commit 4bd1cef1cf
4 changed files with 253 additions and 0 deletions

View 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();