// ======================================== // Memory Page // ======================================== // View and manage core memory and context with CRUD operations import { useState, useEffect } from 'react'; import { useIntl } from 'react-intl'; import { toast } from 'sonner'; import { Brain, Search, Plus, Database, FileText, RefreshCw, Trash2, Edit, Tag, Loader2, Copy, ChevronDown, ChevronUp, Star, Archive, ArchiveRestore, } from 'lucide-react'; import { Card } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import { Input } from '@/components/ui/Input'; import { Badge } from '@/components/ui/Badge'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/Dialog'; import { Checkbox } from '@/components/ui/Checkbox'; import { useMemory, useMemoryMutations } from '@/hooks'; import type { CoreMemory } from '@/lib/api'; import { cn } from '@/lib/utils'; // ========== Memory Card Component ========== interface MemoryCardProps { memory: CoreMemory; isExpanded: boolean; onToggleExpand: () => void; onEdit: (memory: CoreMemory) => void; onDelete: (memory: CoreMemory) => void; onCopy: (content: string) => void; onToggleFavorite: (memory: CoreMemory) => void; onArchive: (memory: CoreMemory) => void; onUnarchive: (memory: CoreMemory) => void; } function MemoryCard({ memory, isExpanded, onToggleExpand, onEdit, onDelete, onCopy, onToggleFavorite, onArchive, onUnarchive }: MemoryCardProps) { const formattedDate = new Date(memory.createdAt).toLocaleDateString(); // Parse metadata from memory const metadata = memory.metadata ? (typeof memory.metadata === 'string' ? JSON.parse(memory.metadata) : memory.metadata) : {}; const isFavorite = metadata.favorite === true; const priority = metadata.priority || 'medium'; const isArchived = memory.archived || false; const formattedSize = memory.size ? memory.size < 1024 ? `${memory.size} B` : `${(memory.size / 1024).toFixed(1)} KB` : 'Unknown'; return ( {/* Header */}
{memory.id} {memory.source && ( {memory.source} )} {priority !== 'medium' && ( {priority} )} {isArchived && ( Archived )}

{formattedDate} - {formattedSize}

{!isArchived ? ( ) : ( )} {isExpanded ? ( ) : ( )}
{/* Preview */} {!isExpanded && (

{memory.content}

)} {/* Tags */} {memory.tags && memory.tags.length > 0 && (
{memory.tags.slice(0, 5).map((tag) => ( {tag} ))} {memory.tags.length > 5 && ( +{memory.tags.length - 5} )}
)}
{/* Expanded Content */} {isExpanded && (
            {memory.content}
          
)}
); } // ========== New Memory Dialog ========== interface NewMemoryDialogProps { open: boolean; onOpenChange: (open: boolean) => void; onSubmit: (data: { content: string; tags?: string[]; metadata?: Record }) => void; isCreating: boolean; editingMemory?: CoreMemory | null; } function NewMemoryDialog({ open, onOpenChange, onSubmit, isCreating, editingMemory, }: NewMemoryDialogProps) { const { formatMessage } = useIntl(); const [content, setContent] = useState(editingMemory?.content || ''); const [tagsInput, setTagsInput] = useState(editingMemory?.tags?.join(', ') || ''); const [isFavorite, setIsFavorite] = useState(false); const [priority, setPriority] = useState<'low' | 'medium' | 'high'>('medium'); // Initialize from editing memory metadata useEffect(() => { if (editingMemory) { // Sync content and tags setContent(editingMemory.content || ''); setTagsInput(editingMemory.tags?.join(', ') || ''); // Sync metadata if (editingMemory.metadata) { try { const metadata = typeof editingMemory.metadata === 'string' ? JSON.parse(editingMemory.metadata) : editingMemory.metadata; setIsFavorite(metadata.favorite === true); setPriority(metadata.priority || 'medium'); } catch { setIsFavorite(false); setPriority('medium'); } } else { setIsFavorite(false); setPriority('medium'); } } else { // New mode: reset all state setContent(''); setTagsInput(''); setIsFavorite(false); setPriority('medium'); } }, [editingMemory]); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (content.trim()) { const tags = tagsInput .split(',') .map((t) => t.trim()) .filter(Boolean); // Build metadata object const metadata: Record = {}; if (isFavorite) metadata.favorite = true; if (priority !== 'medium') metadata.priority = priority; onSubmit({ content: content.trim(), tags: tags.length > 0 ? tags : undefined, metadata: Object.keys(metadata).length > 0 ? metadata : undefined, }); setContent(''); setTagsInput(''); setIsFavorite(false); setPriority('medium'); } }; return ( {editingMemory ? formatMessage({ id: 'memory.createDialog.editTitle' }) : formatMessage({ id: 'memory.createDialog.title' })}