From 355f10964c4dbec24a244a00caba5c17ed23fc65 Mon Sep 17 00:00:00 2001 From: soryu Date: Thu, 12 Feb 2026 02:29:45 +0000 Subject: makima: Add an optional memory system for directives (#59) * feat: makima: Add an optional memory system for directives: Add directive_memories database table and migration * feat: makima: Add an optional memory system for directives: Update directive skill documentation with memory commands * feat: makima: Add an optional memory system for directives: Add repository functions for directive memory CRUD * feat: makima: Add an optional memory system for directives: Add frontend API functions and types for directive memory * feat: makima: Add an optional memory system for directives: Add Rust models for directive memory * WIP: heartbeat checkpoint * WIP: heartbeat checkpoint * WIP: heartbeat checkpoint * WIP: heartbeat checkpoint * feat: makima: Add an optional memory system for directives: Add memory panel to frontend DirectiveDetail component * Merge remote-tracking branch 'origin/makima/makima--add-an-optional-memory-system-for-directiv-5de1e06d' into combined branch * Merge remote-tracking branch 'origin/makima/makima--add-an-optional-memory-system-for-directiv-c8298c6c' into combined branch * feat: makima: Add an optional memory system for directives: Create useMultiTaskSubscription hook for multi-output WebSocket streaming * feat: makima: Add an optional memory system for directives: Create DirectiveLogStream component for stern-like multi-task output viewing * feat: makima: Add an optional memory system for directives: Integrate log stream panel into directive detail page --- makima/frontend/src/hooks/useDirectiveMemories.ts | 119 ++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 makima/frontend/src/hooks/useDirectiveMemories.ts (limited to 'makima/frontend/src/hooks/useDirectiveMemories.ts') 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([]); + const [config, setConfig] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(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>( + (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, + }; +} -- cgit v1.2.3