diff --git a/dashboard/app/layout.tsx b/dashboard/app/layout.tsx index 25158fa3..b72f2379 100644 --- a/dashboard/app/layout.tsx +++ b/dashboard/app/layout.tsx @@ -3,6 +3,7 @@ import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import Sidebar from "@/components/sidebar"; import Navbar from "@/components/navbar"; +import { ProjectProvider } from "@/lib/project-context"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -33,11 +34,13 @@ export default function RootLayout({ className={`${geistSans.variable} ${geistMono.variable} antialiased bg-black text-stone-300`} suppressHydrationWarning > - - -
- {children} -
+ + + +
+ {children} +
+
); diff --git a/dashboard/app/memories/page.tsx b/dashboard/app/memories/page.tsx index dac66b33..ba436c11 100644 --- a/dashboard/app/memories/page.tsx +++ b/dashboard/app/memories/page.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from "react" import { API_BASE_URL, getHeaders } from "@/lib/api" +import { useProject } from "@/lib/project-context" interface mem { id: string @@ -15,6 +16,7 @@ interface mem { salience: number decay_lambda?: number version?: number + project_id?: string } const sectorColors: Record = { @@ -26,6 +28,7 @@ const sectorColors: Record = { } export default function memories() { + const { currentProject } = useProject() const [mems, setmems] = useState([]) const [srch, setsrch] = useState("") const [filt, setfilt] = useState("all") @@ -41,16 +44,18 @@ export default function memories() { useEffect(() => { fetchMems() - }, [page, filt]) + }, [page, filt, currentProject]) async function fetchMems() { setloading(true) seterror(null) try { const offset = (page - 1) * limit - const url = filt !== "all" - ? `${API_BASE_URL}/memory/all?l=${limit}&u=${offset}§or=${filt}` - : `${API_BASE_URL}/memory/all?l=${limit}&u=${offset}` + let url = `${API_BASE_URL}/memory/all?l=${limit}&u=${offset}` + if (filt !== "all") url += `§or=${filt}` + // Append project_id to the query if a project is selected + if (currentProject) url += `&project_id=${currentProject}` + const res = await fetch(url, { headers: getHeaders() }) if (!res.ok) throw new Error('failed to fetch memories') const data = await res.json() @@ -76,7 +81,10 @@ export default function memories() { body: JSON.stringify({ query: srch, k: 1000, - filters: filt !== "all" ? { sector: filt } : undefined, + filters: { + ...(filt !== "all" ? { sector: filt } : {}), + ...(currentProject ? { project_id: currentProject } : {}), + }, }), }) if (!res.ok) throw new Error('search failed') @@ -89,6 +97,7 @@ export default function memories() { tags: [], created_at: m.last_seen_at || Date.now(), salience: m.salience, + project_id: m.project_id })) ) } catch (e: any) { @@ -98,7 +107,7 @@ export default function memories() { } } - async function handleAddMemory(content: string, sector: string, tags: string) { + async function handleAddMemory(content: string, sector: string, tags: string, scope: 'project' | 'global') { try { const res = await fetch(`${API_BASE_URL}/memory/add`, { method: 'POST', @@ -107,6 +116,8 @@ export default function memories() { content, tags: tags.split(',').map((t) => t.trim()).filter(Boolean), metadata: { primary_sector: sector }, + // Explicitly set project_id based on user selected scope + project_id: scope === 'project' ? currentProject : 'system_global' }), }) if (!res.ok) throw new Error('failed to add memory') @@ -164,156 +175,199 @@ export default function memories() { return (
-

Memory Topology

+
+

Memory Topology

+ {currentProject && ( +
+
+ {currentProject} +
+ )} +
-
- Filters +
+ Sectors
-
- Search +
+ Retrieval
- - + + setsrch(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSearch()} - className="w-full bg-stone-950 rounded-xl border border-stone-900 outline-none p-2 pl-10 text-stone-300" - placeholder="Search memories..." + className="w-full bg-stone-950 rounded-xl border border-stone-900 outline-none p-2 pl-10 text-stone-300 focus:border-stone-700 transition-colors" + placeholder="Vector search..." />
-
+
-
-
{sectorCounts.semantic || 0}
-
Semantic
+
+
{sectorCounts.semantic || 0}
+
Semantic
-
-
{sectorCounts.episodic || 0}
-
Episodic
+
+
{sectorCounts.episodic || 0}
+
Episodic
-
-
{sectorCounts.procedural || 0}
-
Procedural
+
+
{sectorCounts.procedural || 0}
+
Procedural
-
-
{sectorCounts.emotional || 0}
-
Emotional
+
+
{sectorCounts.emotional || 0}
+
Emotional
-
-
{sectorCounts.reflective || 0}
-
Reflective
+
+
{sectorCounts.reflective || 0}
+
Reflective
-
-

Memories ({filteredMems.length})

- {loading &&
Loading...
} - {error &&
Error: {error}
} +
+
+

Memory Stream ({filteredMems.length} entries)

+
+
+
+ Realtime +
+
+
+ {loading &&
+
+ Synthesizing memory patterns... +
} + {error &&
+ + Error: {error} +
} {!loading && !error && ( -
+
{filteredMems.length === 0 ? ( -
- No memories found.
Try adjusting your filters.
+
+ + No memory clusters found. +

Adjust your project or sector filters to locate specific knowledge points.

) : ( filteredMems.map((mem) => (
-
-
+
+
-
-

{mem.content}

-
- +
+

{mem.content}

+
+ {mem.primary_sector} - - Salience: {(mem.salience * 100).toFixed(0)}% + + {mem.project_id && ( + + {mem.project_id === 'system_global' ? 'GLOBAL' : mem.project_id} + + )} + +
+ + + Salience: {(mem.salience * 100).toFixed(0)}% - - {new Date(mem.created_at).toLocaleDateString()} + + {new Date(mem.created_at).toLocaleDateString(undefined, { month: 'short', day: 'numeric' })} - {mem.tags?.map(tag => ( - - {tag} - - ))} + + {mem.tags?.length > 0 && ( + <> +
+
+ {mem.tags.map(tag => ( + + #{tag} + + ))} +
+ + )}
-
+
@@ -323,19 +377,19 @@ export default function memories() { )} {!loading && !error && filteredMems.length >= limit && ( -
+
- Page {page} + Page {page} @@ -344,7 +398,7 @@ export default function memories() {
- {showAddModal && setShowAddModal(false)} onAdd={handleAddMemory} />} + {showAddModal && setShowAddModal(false)} onAdd={handleAddMemory} initialProject={currentProject} />} {showEditModal && editingMem && ( void; onAdd: (content: string, sector: string, tags: string) => void }) { +function AddMemoryModal({ onClose, onAdd, initialProject }: { onClose: () => void; onAdd: (content: string, sector: string, tags: string, scope: 'project' | 'global') => void; initialProject: string | null }) { const [content, setContent] = useState('') const [sector, setSector] = useState('semantic') const [tags, setTags] = useState('') + const [scope, setScope] = useState<'project' | 'global'>(initialProject ? 'project' : 'global') return ( -
-
-

Add New Memory

-
+
+
+
- -