/** * @file chatDraft.ts — a Chat pane's unsent prompt (`PaneChat`): its text and * attachments, kept per SESSION in this browser's localStorage * (`agenthub.chat.draft.`), so it survives the pane switching to * its terminal (which unmounts the chat) and a page reload — as the terminal's * own half-typed line survives in tmux. An image's preview (a blob URL) does * not outlive the page, so a restored attachment keeps only its path and name. * Cleared once the prompt is sent (an empty draft removes the key). * @author Nguyễn Ngọc Trí Vĩ */ import type { PromptImage } from "../components/run/RunSetup"; const key = (sessionId: string) => `agenthub.chat.draft.${sessionId}`; export interface ChatDraft { prompt: string; images: PromptImage[]; } export function readChatDraft(sessionId: string): ChatDraft { try { const v = JSON.parse( localStorage.getItem(key(sessionId)) || "null" ) as Partial | null; return { prompt: typeof v?.prompt === "string" ? v.prompt : "", images: Array.isArray(v?.images) ? v.images .filter((i) => typeof i?.path === "string" && typeof i.name === "string") .map((i) => ({ path: i.path, name: i.name })) : [], }; } catch { return { prompt: "", images: [] }; } } export function writeChatDraft(sessionId: string, prompt: string, images: PromptImage[]) { try { if (!prompt && !images.length) localStorage.removeItem(key(sessionId)); else localStorage.setItem( key(sessionId), JSON.stringify({ prompt, images: images.map(({ path, name }) => ({ path, name })) }) ); } catch { /* storage full or blocked: the draft lives for this page only */ } }