diff --git a/src/components/ops/memory-panel.tsx b/src/components/ops/memory-panel.tsx index 6b74b95..70a259c 100644 --- a/src/components/ops/memory-panel.tsx +++ b/src/components/ops/memory-panel.tsx @@ -15,6 +15,18 @@ import { toast } from "sonner"; import { MEMORY_CATEGORIES } from "@/lib/types"; import { IconButton, PanelFrame, RefreshButton, SectionTitle } from "./shared"; + +/** Keys the server generates when the caller supplied none. */ +function isGeneratedKey(key: string): boolean { + return /^memory_[0-9a-f-]{36}$/i.test(key); +} + +/** Enough of a memory to tell one row from another in a label. */ +function previewOf(content: string): string { + const flat = content.replace(/\s+/g, " ").trim(); + return flat.length > 48 ? `${flat.slice(0, 48)}…` : flat; +} + export function MemoryPanel() { const { data, loading, error, refresh } = useAsync(() => api.memory(100), []); const [content, setContent] = React.useState(""); @@ -46,6 +58,17 @@ export function MemoryPanel() { } }; + const copyKey = async (key: string) => { + try { + await navigator.clipboard.writeText(key); + toast.success("Key copied"); + } catch { + // Clipboard is blocked outside a secure context; show the key so it can + // still be selected by hand rather than failing silently. + toast.message(key); + } + }; + const del = async () => { const key = pendingForget?.key; if (!key) return; @@ -65,10 +88,11 @@ export function MemoryPanel() { return (