import { createIcons, Camera, ChevronDown, Database, Edit3, FileScan, FileText, Image, Info, Menu, MessageSquarePlus, Paperclip, Send, Settings2, Scan, ScanSearch, Trash2, Wrench, X, Zap, } from 'lucide'; import DOMPurify from 'dompurify'; import { marked } from 'marked'; import { runtime } from './runtime/runtime.js'; import { MODEL, MODEL_REPO } from './model-config.js'; import { parseGroundingResponse } from './grounding.js'; import { parseDocumentRegions } from './document-parsing.js'; import { imageFilesFromClipboard, imageFilesFromDataTransfer } from './image-input.js'; import { WebcamSession } from './webcam-session.js'; import { executeBuiltin, loadTools, modelToolDefinitions, prepareToolCall, saveTools } from './tools/tool-registry.js'; import { callMcpTool, connectMcpServer, disconnectMcpServer } from './tools/mcp-client.js'; import './styles.css'; const iconSet = { Camera, ChevronDown, Database, Edit3, FileScan, FileText, Image, Info, Menu, MessageSquarePlus, Paperclip, Scan, ScanSearch, Send, Settings2, Trash2, Wrench, X, Zap }; const app = document.querySelector('#app'); let scrollToBottomAfterRender = false; let conversationScrollAfterRender = null; let lightboxItems = []; const SYSTEM_PROMPT_KEY = 'liquid-lfm-system-prompt-v1'; const MCP_SETTINGS_KEY = 'liquid-lfm-mcp-v1'; const TOOL_USE_POLICY = [ 'You are an AI assistant with access to a set of tools.', "Tool use is optional. Only call a tool when the user's request requires information or an action that an available tool can provide. Otherwise, answer directly.", 'If a tool is needed, respond with a tool call using the following format:', '<|tool_call_start|>[tool_function_call_1, tool_function_call_2, ...]<|tool_call_end|>.', 'Each tool function call should use Python-like syntax, e.g., calculate(expression="2 + 2").', 'When a successful tool result includes source_url, include it as a Markdown link in the final answer.', 'If a tool returns an error, explain the error to the user.', 'Be concise and helpful.', ].join(' '); const CHARCUTERIE_SYSTEM_PROMPT = `When asked for bounding boxes for objects, return a valid JSON array. Each array item must be an object with: - image_id: the 0-based index of the image - bbox_2d: [xmin, ymin, xmax, ymax] normalized integer coordinates in [0, 1000] - label: a concise label you choose for the predicted object or region Return one item per visible matching object or region. Return [] if none are visible.`; const POINT_GROUNDING_SYSTEM_PROMPT = `When asked for points corresponding to objects or regions, return a valid JSON array. Each array item must be an object with: - image_id: the 0-based index of the image - point_2d: [x, y] normalized integer coordinates in [0, 1000] - label: a concise label you choose for the predicted object or region Return one item per visible matching object or region. Return [] if none are visible.`; const CHARCUTERIE_USER_PROMPT = 'Provide bounding boxes for the grapes on the far side of the table as well as the nearest glass'; const PAD_THAI_USER_PROMPT = 'How do I make this dish?'; const DOCUMENT_PARSING_PROMPT = `If asked to parse a document, parse it into its layout regions using the following format. The pages are provided as images in reading order. For every region, in reading order across all pages, output a header line immediately followed by the region's content: image_index=