/** * Gallery — persist rendered UI panels + charts for recall. */ import { tool } from '@strands-agents/sdk' import { z } from 'zod' import { get, set } from 'idb-keyval' const GALLERY_KEY = 'careless-gallery' interface GalleryItem { id: string type: 'ui-panel' | 'chart' | 'scene' title: string data: any createdAt: number tags?: string[] } async function loadAll(): Promise { return (await get(GALLERY_KEY)) || [] } async function saveAll(items: GalleryItem[]) { await set(GALLERY_KEY, items) } export const galleryAddTool = tool({ name: 'gallery_add', description: 'Save a UI panel, chart, or 3D scene to the gallery for later recall.', inputSchema: z.object({ type: z.enum(['ui-panel', 'chart', 'scene']), title: z.string(), data: z.string().describe('JSON-serialized data specific to the type'), tags: z.array(z.string()).optional(), }), callback: async (input) => { const all = await loadAll() let data: any = input.data try { data = JSON.parse(input.data) } catch {} const item: GalleryItem = { id: 'gal-' + Math.random().toString(36).slice(2, 10), type: input.type, title: input.title, data, tags: input.tags, createdAt: Date.now(), } all.push(item) await saveAll(all) return JSON.stringify({ status: 'added', id: item.id }) }, }) export const galleryListTool = tool({ name: 'gallery_list', description: 'List saved gallery items (UI panels, charts, 3D scenes).', inputSchema: z.object({ type: z.enum(['ui-panel', 'chart', 'scene']).optional(), tag: z.string().optional(), }), callback: async (input) => { let all = await loadAll() if (input.type) all = all.filter(i => i.type === input.type) if (input.tag) all = all.filter(i => i.tags?.includes(input.tag!)) return JSON.stringify({ status: 'success', count: all.length, items: all.map(i => ({ id: i.id, type: i.type, title: i.title, tags: i.tags, createdAt: i.createdAt })), }) }, }) export const galleryGetTool = tool({ name: 'gallery_get', description: 'Retrieve a gallery item (with full data) by ID.', inputSchema: z.object({ id: z.string() }), callback: async (input) => { const all = await loadAll() const item = all.find(i => i.id === input.id) if (!item) return JSON.stringify({ status: 'error', error: 'not found' }) return JSON.stringify({ status: 'success', item }) }, }) export const galleryDeleteTool = tool({ name: 'gallery_delete', description: 'Delete a gallery item.', inputSchema: z.object({ id: z.string() }), callback: async (input) => { const all = await loadAll() await saveAll(all.filter(i => i.id !== input.id)) return JSON.stringify({ status: 'deleted' }) }, }) export const GALLERY_TOOLS = [galleryAddTool, galleryListTool, galleryGetTool, galleryDeleteTool]