session_save_image
Save image files to a project's visual memory for UI states, diagrams, or bug screenshots. Images are indexed and available in future sessions.
Instructions
Save a local image file into the project's permanent visual memory. Use this to remember UI states, diagrams, architecture graphs, or bug screenshots. The image is copied into Prism's media vault and indexed in the handoff metadata. On the next session_load_context, the agent will see a lightweight index of available images.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project | Yes | Project identifier — must match an existing project. | |
| file_path | Yes | Absolute or relative path to the image file (png, jpg, jpeg, webp, gif, svg). | |
| description | Yes | What does this image show? Used for indexing and context display. |
Implementation Reference
- The handler for `session_save_image` that validates inputs, saves the image to the media vault, and updates handoff metadata.
export async function sessionSaveImageHandler(args: unknown) { if (!isSessionSaveImageArgs(args)) { return { content: [{ type: "text", text: "Invalid arguments. Requires: project, file_path, description." }], isError: true, }; } const { project, file_path, description } = args; // Resolve path (supports relative paths) const resolvedPath = nodePath.resolve(file_path); if (!fs.existsSync(resolvedPath)) { return { content: [{ type: "text", text: `Error: File not found at "${resolvedPath}".` }], isError: true, }; } // Validate extension const ext = nodePath.extname(resolvedPath).toLowerCase() || ".png"; const SUPPORTED_EXTS = [".png", ".jpg", ".jpeg", ".webp", ".gif", ".svg"]; if (!SUPPORTED_EXTS.includes(ext)) { return { content: [{ type: "text", text: `Error: Unsupported image format "${ext}". Supported: ${SUPPORTED_EXTS.join(", ")}.`, }], isError: true, }; } // Setup media vault directory const mediaDir = nodePath.join(os.homedir(), ".prism-mcp", "media", project); if (!fs.existsSync(mediaDir)) { fs.mkdirSync(mediaDir, { recursive: true }); } // Copy to vault with short UUID const imageId = randomUUID().slice(0, 8); const vaultFilename = `${imageId}${ext}`; const vaultPath = nodePath.join(mediaDir, vaultFilename); fs.copyFileSync(resolvedPath, vaultPath); // Update handoff metadata const storage = await getStorage(); const context = await storage.loadContext(project, "quick", PRISM_USER_ID); if (!context) { return { content: [{ type: "text", text: `Error: No active context for project "${project}". Save a handoff first.`, }], isError: true, }; } const contextObj = context as any; const meta = contextObj.metadata || {}; meta.visual_memory = meta.visual_memory || []; meta.visual_memory.push({ id: imageId, description, filename: vaultFilename, original_path: resolvedPath, timestamp: new Date().toISOString(), }); // Save back (triggers history snapshot + telepathy) const handoffUpdate = { project, user_id: PRISM_USER_ID, metadata: meta, last_summary: contextObj.last_summary ?? null, pending_todo: contextObj.pending_todo ?? null, active_decisions: contextObj.active_decisions ?? null, keywords: contextObj.keywords ?? null, key_context: contextObj.key_context ?? null, active_branch: contextObj.active_branch ?? null, }; const currentVersion = contextObj.version; await storage.saveHandoff(handoffUpdate, currentVersion); const fileSize = fs.statSync(vaultPath).size; const sizeKB = (fileSize / 1024).toFixed(1); console.error(`[Visual Memory] Saved image [${imageId}] for "${project}" (${sizeKB}KB, ${ext})`); return { content: [{ type: "text", text: `✅ Image saved to visual memory.\n\n` + `• ID: \`${imageId}\`\n` + `• Description: ${description}\n` + `• Format: ${ext} (${sizeKB}KB)\n` + `• Vault: ${vaultPath}\n\n` + `Use \`session_view_image("${project}", "${imageId}")\` to retrieve it later.`, }], isError: false, }; } - Definition of the `session_save_image` tool schema and argument validation function.
export const SESSION_SAVE_IMAGE_TOOL: Tool = { name: "session_save_image", description: "Save a local image file into the project's permanent visual memory. " + "Use this to remember UI states, diagrams, architecture graphs, or bug screenshots. " + "The image is copied into Prism's media vault and indexed in the handoff metadata. " + "On the next session_load_context, the agent will see a lightweight index of available images.", inputSchema: { type: "object", properties: { project: { type: "string", description: "Project identifier — must match an existing project.", }, file_path: { type: "string", description: "Absolute or relative path to the image file (png, jpg, jpeg, webp, gif, svg).", }, description: { type: "string", description: "What does this image show? Used for indexing and context display.", }, }, required: ["project", "file_path", "description"], }, }; export const SESSION_VIEW_IMAGE_TOOL: Tool = { name: "session_view_image", description: "Retrieve an image from visual memory using its ID. " + "Returns the image as Base64 inline content for the LLM to analyze. " + "Use session_load_context first to see available image IDs.", inputSchema: { type: "object", properties: { project: { type: "string", description: "Project identifier.", }, image_id: { type: "string", description: "The short image ID (e.g., '8f2a1b3c') from the visual memory index.", }, }, required: ["project", "image_id"], }, }; // ─── v2.0: Visual Memory Type Guards ───────────────────────── export function isSessionSaveImageArgs(