import { useState, useEffect, useCallback } from 'react'; import { api } from '../lib/api'; import { relativeTime } from '../lib/utils'; import Card from '../components/Card'; import Badge from '../components/Badge'; // Channel lookup: tab-name → Redis key prefix used by discord_bot.py const TABS = ['STM', 'Lifecycle', 'LPM', 'MAGMA', 'Foresight']; const SHARDS = Array.from({ length: 15 }, (_, i) => ({ id: i, fillPct: 0, vectors: 0 })); // STM tab: reads live from /memory/stm/:channelId function STMTab() { const [channelId, setChannelId] = useState(''); const [inputId, setInputId] = useState(''); const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const fetchSTM = useCallback(async (cid) => { if (!cid) return; setLoading(true); setError(null); try { const d = await api.memory.stm(cid); setData(d); } catch (e) { setError(e.message); } finally { setLoading(false); } }, []); return (
{[['Window', '20 msgs'], ['TTL', '7200s'], ['Scope', 'per channel_id']].map(([k, v]) => (

{k}

{v}

))}
setInputId(e.target.value)} />
{error &&

✗ {error}

} {loading &&

Loading...

} {data && !loading && (

CONTEXT WINDOW

{data.context_window_count}

LIFECYCLE CELLS

{data.lifecycle_cell_count}

{data.context_window?.length > 0 ? (
{data.context_window.map((msg, i) => (
{msg}
))}
) : (

No context. Send a Discord message to populate.

)} {data.lifecycle_cells?.length > 0 && (

Lifecycle Cells

{data.lifecycle_cells.map((cell, i) => (
{cell.tier ?? 'stm'} {cell.created_at ? relativeTime(cell.created_at) : ''}

{cell.content ?? ''}

))}
)}
)} {!data && !loading && !error && (

Enter a Discord channel ID above to view STM.

)}
); } export default function Memory() { const [tab, setTab] = useState('STM'); return (

Memory

STM (Redis) → Lifecycle → RAPTOR → Zilliz x15 unified pipeline.

{TABS.map((t) => ( ))}
{tab === 'STM' && } {tab === 'Lifecycle' && (
{[['Status', 'Active'], ['Heat TTL', '6h'], ['Tiers', 'STM→MTM→LPM']].map(([k, v]) => (

{k}

{v}

))}
{['MemCell', 'heat ↑', 'MemScene', 'abstract', 'Foresight'].map((label, i, arr) => ( {label} {i < arr.length - 1 && i % 2 === 0 && } ))}

lifecycle.py active. Ingests every Discord message + /infer call. MemCells promoted to MemScene after heat threshold (6h TTL). Foresight signal feeds rd_loop.py proposal generation.

)} {tab === 'LPM' && (
{[['Shards', '15'], ['Embedding', '384-dim'], ['Metric', 'COSINE'], ['Model', 'all-MiniLM-L6-v2']].map(([k, v]) => (

{k}

{v}

))}
{SHARDS.map((shard) => (
shard {shard.id}
{shard.fillPct}%
))}

Shard: hash(user_id) % 15. RAPTOR tree summarises clusters before upsert. Live fill % available after Zilliz stats endpoint added.

)} {tab === 'MAGMA' && (
{[['Status', 'Active'], ['Backend', 'NetworkX + Redis'], ['Graphs', '4']].map(([k, v]) => (

{k}

{v}

))}
{[ { name: 'SEMANTIC', desc: 'concept ↔ concept edges' }, { name: 'TEMPORAL', desc: 'event ordering + time' }, { name: 'CAUSAL', desc: 'cause → effect chains' }, { name: 'ENTITY', desc: 'named entities + relations' }, ].map(({ name, desc }) => (

{name}

{desc}

))}

magma_graph.py active. NetworkX in-memory + Redis persistence. D3 force-directed visualisation available in next phase when graph query endpoint is added. +45.5% reasoning accuracy (arXiv:2601.03236).

)} {tab === 'Foresight' && (
{[['Status', 'Active'], ['Source', 'lifecycle.py'], ['Feeds', 'rd_loop.py']].map(([k, v]) => (

{k}

{v}

))}
{['MemScene heat', '→', 'Foresight signal', '→', 'RDLoop.propose()', '→', 'Council debate', '→', 'Implement'].map((label, i) => ( {label} ))}

Foresight predicts what Ghost will need before asking. Drives autonomous R&D proposals visible in Projects tab. Signal strength determined by MemScene heat score over 6h window.

)}
); }