/** * SessionView — List and inspect conversation sessions */ import { useState } from 'react'; import { getSession } from '../api/client'; import type { SessionWithMemories, MemoryItem } from '../api/client'; export default function SessionView() { const [sessionId, setSessionId] = useState(''); const [session, setSession] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const handleFetch = async () => { if (!sessionId) return; setLoading(true); setError(null); try { const data = await getSession(sessionId); setSession(data); } catch (e) { setError(e instanceof Error ? e.message : 'Failed to fetch session'); setSession(null); } finally { setLoading(false); } }; const episodic = session?.memories.filter((m) => m.memory_type === 'episodic') || []; const hasSummary = episodic.some((m) => m.summary); return (

Session View

Inspect conversation sessions and their episodic timeline

{/* Session lookup */}
setSessionId(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleFetch()} style={{ flex: 1, padding: '10px 16px', borderRadius: '10px', border: '1px solid var(--color-border)', background: 'var(--color-surface)', color: 'var(--color-text-primary)', fontSize: '14px', outline: 'none', }} />
{error && (
{error}
)} {session && ( <> {/* Session info */}
{session.ended_at ? 'Completed' : '🔴 Active'} {hasSummary && ( ✓ Summarised )} {session.memories.length} memories
{/* Summary */} {hasSummary && (

Session Summary

{episodic.find((m) => m.summary)?.summary}

)} {/* Episodic Timeline */}

Conversation Timeline

{episodic.sort((a, b) => (a.metadata as Record).turn_index - (b.metadata as Record).turn_index).map((mem) => ( ))}
)}
); } function InfoItem({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); } function TimelineItem({ memory }: { memory: MemoryItem }) { const meta = memory.metadata as Record; const userMsg = meta.user_message as string || ''; const asstMsg = meta.assistant_message as string || ''; const turnIdx = meta.turn_index as number ?? 0; return (
{/* Timeline dot */}
{/* Content */}
Turn {turnIdx}
{userMsg}
{asstMsg}
); }