diff options
| author | soryu <soryu@soryu.co> | 2026-02-12 23:37:44 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-12 23:37:44 +0000 |
| commit | d1b4f56109d4900c76c27b6a35763694323046af (patch) | |
| tree | aafc1825dfc4aaed2129b2a376010ad8e9556a42 | |
| parent | 355f10964c4dbec24a244a00caba5c17ed23fc65 (diff) | |
| download | soryu-makima/makima-jp--remove-memory-system-from-frontend-228e0bd0.tar.gz soryu-makima/makima-jp--remove-memory-system-from-frontend-228e0bd0.zip | |
feat: makima.jp: Remove memory system from frontendmakima/makima-jp--remove-memory-system-from-frontend-228e0bd0
| -rw-r--r-- | makima/frontend/src/components/directives/DirectiveDetail.tsx | 261 | ||||
| -rw-r--r-- | makima/frontend/src/hooks/useDirectiveMemories.ts | 119 | ||||
| -rw-r--r-- | makima/frontend/src/lib/api.ts | 185 |
3 files changed, 1 insertions, 564 deletions
diff --git a/makima/frontend/src/components/directives/DirectiveDetail.tsx b/makima/frontend/src/components/directives/DirectiveDetail.tsx index ab6ddbb..39eaa3f 100644 --- a/makima/frontend/src/components/directives/DirectiveDetail.tsx +++ b/makima/frontend/src/components/directives/DirectiveDetail.tsx @@ -1,8 +1,7 @@ import { useState, useMemo, useEffect, useRef } from "react"; -import type { DirectiveWithSteps, DirectiveStatus, MemoryCategory } from "../../lib/api"; +import type { DirectiveWithSteps, DirectiveStatus } from "../../lib/api"; import { DirectiveDAG } from "./DirectiveDAG"; import { DirectiveLogStream } from "./DirectiveLogStream"; -import { useDirectiveMemories } from "../../hooks/useDirectiveMemories"; import { useMultiTaskSubscription } from "../../hooks/useMultiTaskSubscription"; const STATUS_BADGE: Record<DirectiveStatus, { color: string; label: string }> = { @@ -13,16 +12,6 @@ const STATUS_BADGE: Record<DirectiveStatus, { color: string; label: string }> = archived: { color: "text-[#556677] border-[#2a3a5a]", label: "ARCHIVED" }, }; -const CATEGORY_COLORS: Record<MemoryCategory, { text: string; border: string; bg: string; label: string }> = { - decision: { text: "text-amber-400", border: "border-amber-800", bg: "bg-amber-900/20", label: "Decision" }, - context: { text: "text-cyan-400", border: "border-cyan-800", bg: "bg-cyan-900/20", label: "Context" }, - preference: { text: "text-violet-400", border: "border-violet-800", bg: "bg-violet-900/20", label: "Preference" }, - learning: { text: "text-emerald-400", border: "border-emerald-800", bg: "bg-emerald-900/20", label: "Learning" }, - other: { text: "text-[#7788aa]", border: "border-[#2a3a5a]", bg: "bg-[#1a2540]", label: "Other" }, -}; - -const ALL_CATEGORIES: MemoryCategory[] = ["decision", "context", "preference", "learning", "other"]; - interface DirectiveDetailProps { directive: DirectiveWithSteps; onStart: () => void; @@ -60,29 +49,6 @@ export function DirectiveDetail({ const totalSteps = directive.steps.length; const progress = totalSteps > 0 ? Math.round((completedSteps / totalSteps) * 100) : 0; - // Memory panel state - const [memoryOpen, setMemoryOpen] = useState(false); - const [addingMemory, setAddingMemory] = useState(false); - const [newCategory, setNewCategory] = useState<MemoryCategory>("context"); - const [newContent, setNewContent] = useState(""); - const [newSource, setNewSource] = useState(""); - const [confirmClear, setConfirmClear] = useState(false); - - const { - grouped, - config: memoryConfig, - loading: memoryLoading, - error: memoryError, - toggleEnabled, - add: addMemory, - remove: removeMemory, - clearAll: clearMemories, - refresh: refreshMemories, - } = useDirectiveMemories(directive.id); - - const memoryEnabled = memoryConfig?.enabled ?? false; - const totalMemories = Object.values(grouped).reduce((sum, arr) => sum + arr.length, 0); - // Build task map from directive steps and orchestrator const taskMap = useMemo(() => { const map = new Map<string, string>(); @@ -121,23 +87,6 @@ export function DirectiveDetail({ setEditingGoal(false); }; - const handleAddMemory = async () => { - if (!newContent.trim()) return; - await addMemory({ - category: newCategory, - content: newContent.trim(), - source: newSource.trim() || undefined, - }); - setNewContent(""); - setNewSource(""); - setAddingMemory(false); - }; - - const handleClearAll = async () => { - await clearMemories(); - setConfirmClear(false); - }; - return ( <div className="flex flex-col h-full overflow-y-auto"> {/* Header */} @@ -337,214 +286,6 @@ export function DirectiveDetail({ )} </div> - {/* Memory Panel */} - <div className="px-4 py-3 border-b border-[rgba(117,170,252,0.1)]"> - {/* Memory header — always visible */} - <div className="flex items-center justify-between"> - <button - type="button" - onClick={() => setMemoryOpen((v) => !v)} - className="flex items-center gap-1.5 group" - > - <span className="text-[10px] font-mono text-[#556677] group-hover:text-[#9bc3ff] transition-colors"> - {memoryOpen ? "\u25BC" : "\u25B6"} - </span> - <span className="text-[10px] font-mono text-[#9bc3ff] uppercase tracking-wide"> - Memory - </span> - {totalMemories > 0 && ( - <span className="text-[9px] font-mono text-[#556677] ml-1"> - ({totalMemories}) - </span> - )} - </button> - <div className="flex items-center gap-2"> - {/* Enable/disable toggle */} - <button - type="button" - onClick={() => toggleEnabled(!memoryEnabled)} - className={`text-[9px] font-mono border rounded px-1.5 py-0.5 transition-colors ${ - memoryEnabled - ? "text-emerald-400 border-emerald-800 hover:text-emerald-300" - : "text-[#556677] border-[#2a3a5a] hover:text-[#7788aa]" - }`} - title={memoryEnabled ? "Disable memory" : "Enable memory"} - > - {memoryEnabled ? "ON" : "OFF"} - </button> - </div> - </div> - - {/* Collapsible content */} - {memoryOpen && ( - <div className="mt-2"> - {memoryError && ( - <div className="text-[10px] font-mono text-red-400 mb-2 px-2 py-1 bg-red-900/10 border border-red-800/30 rounded"> - {memoryError} - </div> - )} - - {memoryLoading ? ( - <div className="text-[10px] font-mono text-[#556677] py-2">Loading...</div> - ) : totalMemories === 0 ? ( - <div className="text-[10px] font-mono text-[#556677] py-2"> - No memory entries yet. - {!memoryEnabled && " Enable memory to start capturing entries."} - </div> - ) : ( - /* Grouped entries */ - <div className="flex flex-col gap-2"> - {ALL_CATEGORIES.map((cat) => { - const entries = grouped[cat]; - if (entries.length === 0) return null; - const style = CATEGORY_COLORS[cat]; - return ( - <div key={cat}> - <div className="flex items-center gap-1.5 mb-1"> - <span className={`text-[9px] font-mono ${style.text} uppercase tracking-wider`}> - {style.label} - </span> - <span className="text-[9px] font-mono text-[#556677]"> - ({entries.length}) - </span> - </div> - <div className="flex flex-col gap-1"> - {entries.map((entry) => ( - <div - key={entry.id} - className={`flex items-start gap-2 px-2 py-1.5 rounded border ${style.border} ${style.bg}`} - > - <div className="flex-1 min-w-0"> - <p className="text-[10px] font-mono text-[#c0d0e0] whitespace-pre-wrap break-words"> - {entry.content} - </p> - {entry.source && ( - <span className="text-[9px] font-mono text-[#556677] mt-0.5 block"> - src: {entry.source} - </span> - )} - </div> - <button - type="button" - onClick={() => removeMemory(entry.id)} - className="text-[9px] font-mono text-[#556677] hover:text-red-400 shrink-0 mt-0.5" - title="Delete entry" - > - x - </button> - </div> - ))} - </div> - </div> - ); - })} - </div> - )} - - {/* Action bar: Add + Clear */} - <div className="flex items-center gap-2 mt-2 pt-2 border-t border-[rgba(117,170,252,0.1)]"> - <button - type="button" - onClick={() => setAddingMemory((v) => !v)} - className="text-[10px] font-mono text-[#75aafc] hover:text-white border border-[rgba(117,170,252,0.2)] rounded px-2 py-0.5" - > - {addingMemory ? "Cancel" : "+ Add"} - </button> - {totalMemories > 0 && ( - <> - {confirmClear ? ( - <div className="flex items-center gap-1.5 ml-auto"> - <span className="text-[9px] font-mono text-red-400">Clear all?</span> - <button - type="button" - onClick={handleClearAll} - className="text-[9px] font-mono text-red-400 hover:text-red-300 border border-red-800 rounded px-1.5 py-0.5" - > - Yes - </button> - <button - type="button" - onClick={() => setConfirmClear(false)} - className="text-[9px] font-mono text-[#7788aa] hover:text-white border border-[#2a3a5a] rounded px-1.5 py-0.5" - > - No - </button> - </div> - ) : ( - <button - type="button" - onClick={() => setConfirmClear(true)} - className="text-[10px] font-mono text-[#556677] hover:text-red-400 ml-auto" - > - Clear all - </button> - )} - </> - )} - <button - type="button" - onClick={refreshMemories} - className="text-[9px] font-mono text-[#556677] hover:text-[#75aafc]" - title="Refresh memories" - > - [refresh] - </button> - </div> - - {/* Add form */} - {addingMemory && ( - <div className="mt-2 p-2 bg-[#0a1628] border border-[rgba(117,170,252,0.15)] rounded flex flex-col gap-2"> - <div className="flex items-center gap-2"> - <label className="text-[9px] font-mono text-[#7788aa] shrink-0">Category</label> - <select - value={newCategory} - onChange={(e) => setNewCategory(e.target.value as MemoryCategory)} - className="bg-[#1a2540] border border-[rgba(117,170,252,0.2)] rounded px-1.5 py-0.5 text-[10px] font-mono text-white flex-1" - > - {ALL_CATEGORIES.map((c) => ( - <option key={c} value={c}> - {CATEGORY_COLORS[c].label} - </option> - ))} - </select> - </div> - <textarea - value={newContent} - onChange={(e) => setNewContent(e.target.value)} - placeholder="Memory content..." - className="w-full bg-[#1a2540] border border-[rgba(117,170,252,0.2)] rounded px-2 py-1.5 text-[10px] font-mono text-white resize-y min-h-[40px] placeholder:text-[#556677]" - rows={2} - /> - <input - type="text" - value={newSource} - onChange={(e) => setNewSource(e.target.value)} - placeholder="Source (optional)" - className="w-full bg-[#1a2540] border border-[rgba(117,170,252,0.2)] rounded px-2 py-1 text-[10px] font-mono text-white placeholder:text-[#556677]" - /> - <div className="flex gap-1.5"> - <button - type="button" - onClick={handleAddMemory} - disabled={!newContent.trim()} - className="text-[10px] font-mono text-emerald-400 hover:text-emerald-300 border border-emerald-800 rounded px-2 py-0.5 disabled:opacity-40 disabled:cursor-not-allowed" - > - Save - </button> - <button - type="button" - onClick={() => { setAddingMemory(false); setNewContent(""); setNewSource(""); }} - className="text-[10px] font-mono text-[#7788aa] hover:text-white border border-[#2a3a5a] rounded px-2 py-0.5" - > - Cancel - </button> - </div> - </div> - )} - </div> - )} - </div> - {/* DAG */} <div className="px-4 py-3 flex-1"> <span className="text-[10px] font-mono text-[#9bc3ff] uppercase tracking-wide block mb-2"> diff --git a/makima/frontend/src/hooks/useDirectiveMemories.ts b/makima/frontend/src/hooks/useDirectiveMemories.ts deleted file mode 100644 index 3844c44..0000000 --- a/makima/frontend/src/hooks/useDirectiveMemories.ts +++ /dev/null @@ -1,119 +0,0 @@ -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, - }; -} diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts index 552829a..9d1f0ad 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -3023,8 +3023,6 @@ export interface Directive { prUrl: string | null; prBranch: string | null; completionTaskId: string | null; - /** Whether the memory system is enabled for this directive */ - memoryEnabled: boolean; goalUpdatedAt: string; startedAt: string | null; version: number; @@ -3062,8 +3060,6 @@ export interface DirectiveSummary { orchestratorTaskId: string | null; prUrl: string | null; completionTaskId: string | null; - /** Whether the memory system is enabled for this directive */ - memoryEnabled: boolean; version: number; createdAt: string; updatedAt: string; @@ -3084,8 +3080,6 @@ export interface CreateDirectiveRequest { repositoryUrl?: string; localPath?: string; baseBranch?: string; - /** Enable the memory system for this directive (default: false) */ - memoryEnabled?: boolean; } export interface UpdateDirectiveRequest { @@ -3096,8 +3090,6 @@ export interface UpdateDirectiveRequest { localPath?: string; baseBranch?: string; orchestratorTaskId?: string; - /** Enable or disable the memory system for this directive */ - memoryEnabled?: boolean; version?: number; } @@ -3237,180 +3229,3 @@ export async function updateDirectiveGoal(id: string, goal: string): Promise<Dir if (!res.ok) throw new Error(`Failed to update goal: ${res.statusText}`); return res.json(); } - -// ============================================================================= -// Directive Memory Types & API -// ============================================================================= - -/** Category of a directive memory entry */ -export type MemoryCategory = - | "decision" - | "learning" - | "context" - | "preference" - | "issue" - | "progress" - | "other"; - -/** A single memory entry associated with a directive */ -export interface DirectiveMemory { - id: string; - directiveId: string; - /** The memory content text */ - content: string; - /** Category for organizing memories */ - category: MemoryCategory; - /** Which step created this memory (null if directive-level) */ - stepId: string | null; - /** Which task created this memory (null if manually added) */ - taskId: string | null; - /** Importance score (1-10, higher = more important) */ - importance: number; - createdAt: string; - updatedAt: string; -} - -/** Response from listing directive memories */ -export interface DirectiveMemoryListResponse { - memories: DirectiveMemory[]; - total: number; -} - -/** Request to create a new directive memory */ -export interface CreateDirectiveMemoryRequest { - content: string; - category?: MemoryCategory; - stepId?: string; - taskId?: string; - importance?: number; -} - -/** Request to update a directive memory */ -export interface UpdateDirectiveMemoryRequest { - content?: string; - category?: MemoryCategory; - importance?: number; -} - -// Directive Memory API functions - -/** - * List all memories for a directive. - * Optionally filter by category or step. - */ -export async function listDirectiveMemories( - directiveId: string, - params?: { category?: MemoryCategory; stepId?: string } -): Promise<DirectiveMemoryListResponse> { - const searchParams = new URLSearchParams(); - if (params?.category) searchParams.set("category", params.category); - if (params?.stepId) searchParams.set("stepId", params.stepId); - const query = searchParams.toString(); - const url = `${API_BASE}/api/v1/directives/${directiveId}/memories${query ? `?${query}` : ""}`; - const res = await authFetch(url); - if (!res.ok) throw new Error(`Failed to list directive memories: ${res.statusText}`); - return res.json(); -} - -/** - * Get a single memory entry by ID. - */ -export async function getDirectiveMemory( - directiveId: string, - memoryId: string -): Promise<DirectiveMemory> { - const res = await authFetch( - `${API_BASE}/api/v1/directives/${directiveId}/memories/${memoryId}` - ); - if (!res.ok) throw new Error(`Failed to get directive memory: ${res.statusText}`); - return res.json(); -} - -/** - * Create a new memory entry for a directive. - */ -export async function createDirectiveMemory( - directiveId: string, - req: CreateDirectiveMemoryRequest -): Promise<DirectiveMemory> { - const res = await authFetch(`${API_BASE}/api/v1/directives/${directiveId}/memories`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(req), - }); - if (!res.ok) throw new Error(`Failed to create directive memory: ${res.statusText}`); - return res.json(); -} - -/** - * Update an existing memory entry. - */ -export async function updateDirectiveMemory( - directiveId: string, - memoryId: string, - req: UpdateDirectiveMemoryRequest -): Promise<DirectiveMemory> { - const res = await authFetch( - `${API_BASE}/api/v1/directives/${directiveId}/memories/${memoryId}`, - { - method: "PUT", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(req), - } - ); - if (!res.ok) throw new Error(`Failed to update directive memory: ${res.statusText}`); - return res.json(); -} - -/** - * Delete a memory entry. - */ -export async function deleteDirectiveMemory( - directiveId: string, - memoryId: string -): Promise<void> { - const res = await authFetch( - `${API_BASE}/api/v1/directives/${directiveId}/memories/${memoryId}`, - { method: "DELETE" } - ); - if (!res.ok) throw new Error(`Failed to delete directive memory: ${res.statusText}`); -} - -/** - * Batch create multiple memory entries for a directive. - * Useful when a task completes and wants to store multiple learnings at once. - */ -export async function batchCreateDirectiveMemories( - directiveId: string, - memories: CreateDirectiveMemoryRequest[] -): Promise<DirectiveMemory[]> { - const res = await authFetch( - `${API_BASE}/api/v1/directives/${directiveId}/memories/batch`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(memories), - } - ); - if (!res.ok) throw new Error(`Failed to batch create directive memories: ${res.statusText}`); - return res.json(); -} - -/** - * Get a formatted memory context string for a directive. - * This returns memories formatted for injection into task prompts. - * Optionally filter by category or limit the number of memories returned. - */ -export async function getDirectiveMemoryContext( - directiveId: string, - params?: { category?: MemoryCategory; limit?: number } -): Promise<{ context: string; memoryCount: number }> { - const searchParams = new URLSearchParams(); - if (params?.category) searchParams.set("category", params.category); - if (params?.limit) searchParams.set("limit", params.limit.toString()); - const query = searchParams.toString(); - const url = `${API_BASE}/api/v1/directives/${directiveId}/memories/context${query ? `?${query}` : ""}`; - const res = await authFetch(url); - if (!res.ok) throw new Error(`Failed to get directive memory context: ${res.statusText}`); - return res.json(); -} |
