diff options
Diffstat (limited to 'makima/frontend/src/hooks/useDirectiveMemories.ts')
| -rw-r--r-- | makima/frontend/src/hooks/useDirectiveMemories.ts | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/makima/frontend/src/hooks/useDirectiveMemories.ts b/makima/frontend/src/hooks/useDirectiveMemories.ts new file mode 100644 index 0000000..3844c44 --- /dev/null +++ b/makima/frontend/src/hooks/useDirectiveMemories.ts @@ -0,0 +1,119 @@ +import { useState, useEffect, useCallback } from "react"; +import { + type DirectiveMemoryEntry, + type DirectiveMemoryConfig, + type MemoryCategory, + type CreateDirectiveMemoryRequest, + getDirectiveMemoryConfig, + setDirectiveMemoryEnabled, + listDirectiveMemories, + addDirectiveMemory, + deleteDirectiveMemory, + clearDirectiveMemories, +} from "../lib/api"; + +export function useDirectiveMemories(directiveId: string | undefined) { + const [memories, setMemories] = useState<DirectiveMemoryEntry[]>([]); + const [config, setConfig] = useState<DirectiveMemoryConfig | null>(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState<string | null>(null); + + const refreshConfig = useCallback(async () => { + if (!directiveId) return; + try { + const c = await getDirectiveMemoryConfig(directiveId); + setConfig(c); + } catch (e) { + // Config may not exist yet — treat as disabled + setConfig({ directiveId, enabled: false, updatedAt: new Date().toISOString() }); + } + }, [directiveId]); + + const refreshMemories = useCallback(async () => { + if (!directiveId) return; + try { + setLoading(true); + setError(null); + const entries = await listDirectiveMemories(directiveId); + setMemories(entries); + } catch (e) { + setError(e instanceof Error ? e.message : "Failed to load memories"); + } finally { + setLoading(false); + } + }, [directiveId]); + + const refresh = useCallback(async () => { + await Promise.all([refreshConfig(), refreshMemories()]); + }, [refreshConfig, refreshMemories]); + + useEffect(() => { + refresh(); + }, [refresh]); + + const toggleEnabled = useCallback(async (enabled: boolean) => { + if (!directiveId) return; + try { + setError(null); + const c = await setDirectiveMemoryEnabled(directiveId, enabled); + setConfig(c); + } catch (e) { + setError(e instanceof Error ? e.message : "Failed to toggle memory"); + } + }, [directiveId]); + + const add = useCallback(async (req: CreateDirectiveMemoryRequest) => { + if (!directiveId) return; + try { + setError(null); + await addDirectiveMemory(directiveId, req); + await refreshMemories(); + } catch (e) { + setError(e instanceof Error ? e.message : "Failed to add memory"); + } + }, [directiveId, refreshMemories]); + + const remove = useCallback(async (memoryId: string) => { + if (!directiveId) return; + try { + setError(null); + await deleteDirectiveMemory(directiveId, memoryId); + await refreshMemories(); + } catch (e) { + setError(e instanceof Error ? e.message : "Failed to delete memory"); + } + }, [directiveId, refreshMemories]); + + const clearAll = useCallback(async () => { + if (!directiveId) return; + try { + setError(null); + await clearDirectiveMemories(directiveId); + setMemories([]); + } catch (e) { + setError(e instanceof Error ? e.message : "Failed to clear memories"); + } + }, [directiveId]); + + /** Group entries by category */ + const grouped = memories.reduce<Record<MemoryCategory, DirectiveMemoryEntry[]>>( + (acc, entry) => { + acc[entry.category].push(entry); + return acc; + }, + { decision: [], context: [], preference: [], learning: [], other: [] }, + ); + + return { + memories, + grouped, + config, + loading, + error, + refresh, + toggleEnabled, + add, + remove, + clearAll, + }; +} |
