/** * MemoryOS — Frontend API Client * * Typed fetch wrapper for all backend endpoints. */ const API_BASE = import.meta.env.VITE_API_URL || '/api/v1'; // ── Types ──────────────────────────────────────────────────────────────── export interface User { id: string; external_id: string; created_at: string; } export interface Session { id: string; user_id: string; started_at: string; ended_at: string | null; metadata: Record; } export interface MemoryItem { id: string; user_id: string; session_id: string | null; memory_type: 'episodic' | 'semantic' | 'procedural'; content: string; summary: string | null; metadata: Record; importance: number; recency_score: number; access_count: number; created_at: string; last_accessed: string | null; } export interface ScoredMemory { memory: MemoryItem; score: number; cosine_similarity: number; } export interface IngestResponse { memory_id: string; message: string; } export interface ChatResponse { assistant_message: string; retrieved_memories: { id: string; type: string; content: string; score: number; }[]; } export interface ContradictionItem { id: string; memory_a: string; memory_b: string; detected_at: string; resolved: boolean; memory_a_content: string | null; memory_b_content: string | null; } export interface StatsOverview { total_memories: number; type_counts: { episodic: number; semantic: number; procedural: number; }; avg_importance: number; avg_recency_score: number; total_users: number; total_sessions: number; recent_contradictions: ContradictionItem[]; } export interface GraphNode { id: string; memory_type: 'episodic' | 'semantic' | 'procedural'; content: string; importance: number; created_at: string; } export interface GraphEdge { source: string; target: string; similarity: number; } export interface GraphData { nodes: GraphNode[]; edges: GraphEdge[]; } export interface SessionWithMemories extends Session { memories: MemoryItem[]; } // ── Fetch helper ───────────────────────────────────────────────────────── async function apiFetch( path: string, options: RequestInit = {} ): Promise { const url = `${API_BASE}${path}`; const headers: Record = { 'Content-Type': 'application/json', ...(options.headers as Record || {}), }; const response = await fetch(url, { ...options, headers }); if (!response.ok) { const body = await response.json().catch(() => ({ detail: response.statusText })); throw new Error(body.detail || `API error: ${response.status}`); } return response.json(); } // ── API functions ──────────────────────────────────────────────────────── export async function createUser(externalId: string): Promise { return apiFetch('/users', { method: 'POST', body: JSON.stringify({ external_id: externalId }), }); } export async function getUser(userId: string): Promise { return apiFetch(`/users/${userId}`); } export async function getUserContext( userId: string, query: string, topK: number = 10 ): Promise { const params = new URLSearchParams({ query, top_k: String(topK) }); return apiFetch(`/users/${userId}/context?${params}`); } export async function createSession( userId: string, metadata: Record = {} ): Promise { return apiFetch('/sessions', { method: 'POST', body: JSON.stringify({ user_id: userId, metadata }), }); } export async function getSession(sessionId: string): Promise { return apiFetch(`/sessions/${sessionId}`); } export async function endSession(sessionId: string): Promise { return apiFetch(`/sessions/${sessionId}`, { method: 'DELETE' }); } export async function sendChatMessage( sessionId: string, userMessage: string ): Promise { return apiFetch(`/sessions/${sessionId}/chat`, { method: 'POST', body: JSON.stringify({ user_message: userMessage }), }); } export async function ingestMemory( userId: string, sessionId: string, userMessage: string, assistantMessage: string ): Promise { return apiFetch('/memories/ingest', { method: 'POST', body: JSON.stringify({ user_id: userId, session_id: sessionId, user_message: userMessage, assistant_message: assistantMessage, }), }); } export async function searchMemories( userId: string, query: string, memoryType?: string, topK: number = 10 ): Promise { const params = new URLSearchParams({ user_id: userId, query, top_k: String(topK), }); if (memoryType) params.append('memory_type', memoryType); return apiFetch(`/memories/search?${params}`); } export async function getMemory(memoryId: string): Promise { return apiFetch(`/memories/${memoryId}`); } export async function deleteMemory(memoryId: string): Promise { return apiFetch(`/memories/${memoryId}`, { method: 'DELETE' }); } export async function getContradictions(memoryId: string): Promise { return apiFetch(`/memories/${memoryId}/contradictions`); } export async function getStatsOverview(): Promise { return apiFetch('/stats/overview'); } export async function getGraphData(userId?: string): Promise { const params = userId ? `?user_id=${userId}` : ''; return apiFetch(`/stats/graph${params}`); }