/** * MI Tool Schema β€” lightweight registry of canvas shape types and module * content types with keyword matching, so MI can suggest relevant tools * as clickable chips. */ export interface ToolHint { tagName: string; label: string; icon: string; keywords: string[]; /** If set, this is a module action rather than a canvas shape. */ moduleAction?: { module: string; contentType: string }; } const TOOL_HINTS: ToolHint[] = [ { tagName: "folk-markdown", label: "Note", icon: "πŸ“", keywords: ["note", "text", "markdown", "write", "document"] }, { tagName: "folk-slide", label: "Slide", icon: "πŸ–ΌοΈ", keywords: ["slide", "presentation", "deck"] }, { tagName: "folk-chat", label: "Chat", icon: "πŸ’¬", keywords: ["chat", "message", "conversation", "talk"] }, { tagName: "folk-embed", label: "Embed", icon: "πŸ”—", keywords: ["embed", "iframe", "website", "url", "link"] }, { tagName: "folk-calendar", label: "Calendar", icon: "πŸ“…", keywords: ["calendar", "date", "schedule", "event"] }, { tagName: "folk-map", label: "Map", icon: "πŸ—ΊοΈ", keywords: ["map", "location", "place", "geo"] }, { tagName: "folk-image-gen", label: "AI Image", icon: "🎨", keywords: ["image", "picture", "photo", "generate", "art", "draw"] }, { tagName: "folk-image-studio", label: "Image Studio", icon: "πŸ–ŒοΈ", keywords: ["image", "brand", "style", "redesign", "img2img", "reference", "consistency", "studio"] }, { tagName: "folk-video-gen", label: "AI Video", icon: "🎬", keywords: ["video", "clip", "animate", "movie", "film"] }, { tagName: "folk-prompt", label: "AI Chat", icon: "πŸ€–", keywords: ["ai", "prompt", "llm", "assistant", "gpt"] }, { tagName: "folk-transcription", label: "Transcribe", icon: "πŸŽ™οΈ", keywords: ["transcribe", "audio", "speech", "voice", "record"] }, { tagName: "folk-video-chat", label: "Video Call", icon: "πŸ“Ή", keywords: ["video call", "webcam", "peer to peer"] }, { tagName: "folk-rapp", label: "rMeets", icon: "πŸ“Ή", keywords: ["meeting", "jitsi", "video", "meet", "conference", "rmeets"] }, { tagName: "folk-workflow-block", label: "Workflow", icon: "βš™οΈ", keywords: ["workflow", "automation", "block", "process"] }, { tagName: "folk-social-post", label: "Social Post", icon: "πŸ“£", keywords: ["social", "post", "twitter", "instagram", "campaign"] }, { tagName: "folk-social-thread", label: "Thread", icon: "🧡", keywords: ["thread", "tweetstorm", "twitter thread", "tweets", "multi-post"] }, { tagName: "folk-social-campaign", label: "Campaign", icon: "πŸ“’", keywords: ["campaign", "launch", "marketing", "social campaign", "content plan"] }, { tagName: "folk-social-newsletter", label: "Newsletter", icon: "πŸ“§", keywords: ["newsletter", "email", "mailout", "subscriber", "mailing list"] }, { tagName: "folk-splat", label: "3D Gaussian", icon: "πŸ’Ž", keywords: ["3d", "splat", "gaussian", "point cloud"] }, { tagName: "folk-drawfast", label: "Drawing", icon: "✏️", keywords: ["draw", "sketch", "whiteboard", "pencil"] }, { tagName: "folk-rapp", label: "rApp Embed", icon: "πŸ“¦", keywords: ["rapp", "module", "embed", "app", "crm", "contacts", "pipeline", "companies"] }, { tagName: "folk-feed", label: "Feed", icon: "πŸ“‘", keywords: ["feed", "data", "stream", "flow"] }, { tagName: "folk-piano", label: "Piano", icon: "🎹", keywords: ["piano", "music", "instrument", "midi"] }, { tagName: "folk-choice-vote", label: "Vote", icon: "πŸ—³οΈ", keywords: ["vote", "poll", "election", "choice"] }, { tagName: "folk-choice-rank", label: "Ranking", icon: "πŸ“Š", keywords: ["rank", "order", "priority", "sort"] }, { tagName: "folk-choice-spider", label: "Spider Chart", icon: "πŸ•ΈοΈ", keywords: ["spider", "radar", "criteria", "evaluate"] }, { tagName: "folk-spider-3d", label: "3D Spider", icon: "πŸ“Š", keywords: ["spider", "radar", "3d", "overlap", "membrane", "governance", "permeability"] }, { tagName: "folk-choice-conviction", label: "Conviction Vote", icon: "πŸ”₯", keywords: ["conviction", "stake", "weight", "governance", "token vote"] }, // Travel { tagName: "folk-itinerary", label: "Itinerary", icon: "πŸ—“οΈ", keywords: ["itinerary", "trip", "travel", "plan", "schedule"] }, { tagName: "folk-destination", label: "Destination", icon: "πŸ“", keywords: ["destination", "city", "place", "travel", "visit"] }, { tagName: "folk-booking", label: "Booking", icon: "🎫", keywords: ["booking", "reservation", "flight", "hotel", "transport"] }, { tagName: "folk-budget", label: "Budget", icon: "πŸ’°", keywords: ["budget", "expense", "cost", "money", "spending"] }, { tagName: "folk-packing-list", label: "Packing List", icon: "πŸŽ’", keywords: ["packing", "list", "luggage", "gear", "pack"] }, // Tokens { tagName: "folk-token-mint", label: "Token Mint", icon: "πŸͺ™", keywords: ["token", "mint", "create token", "currency", "coin"] }, { tagName: "folk-token-ledger", label: "Token Ledger", icon: "πŸ“’", keywords: ["ledger", "balance", "token", "transactions", "holdings"] }, { tagName: "folk-transaction-builder", label: "Transaction", icon: "πŸ’Έ", keywords: ["transaction", "transfer", "send", "multisig", "safe"] }, // Creative / CAD { tagName: "folk-blender", label: "3D Scene", icon: "🎲", keywords: ["blender", "3d", "render", "scene", "model"] }, { tagName: "folk-freecad", label: "CAD Part", icon: "πŸ”§", keywords: ["cad", "freecad", "part", "mechanical", "parametric"] }, { tagName: "folk-kicad", label: "PCB Design", icon: "πŸ”Œ", keywords: ["pcb", "kicad", "circuit", "schematic", "electronics"] }, { tagName: "folk-design-agent", label: "Print Design", icon: "πŸ–¨οΈ", keywords: ["design", "poster", "flyer", "brochure", "print", "layout", "scribus"] }, // Zine { tagName: "folk-zine-gen", label: "Zine", icon: "πŸ“°", keywords: ["zine", "magazine", "publication", "pamphlet", "print"] }, // Geo { tagName: "folk-holon", label: "Holon", icon: "🌐", keywords: ["holon", "h3", "hexagon", "geospatial", "region"] }, { tagName: "folk-holon-browser", label: "Holon Browser", icon: "🌍", keywords: ["holon", "browse", "explore", "territory", "map"] }, // Meta { tagName: "folk-canvas", label: "Nested Canvas", icon: "πŸ”²", keywords: ["canvas", "nested", "subspace", "embed canvas"] }, { tagName: "folk-wrapper", label: "Wrapper", icon: "πŸ“¦", keywords: ["wrapper", "container", "group", "frame"] }, { tagName: "folk-image", label: "Image", icon: "πŸ–ΌοΈ", keywords: ["image", "photo", "picture", "png", "jpg"] }, { tagName: "folk-bookmark", label: "Bookmark", icon: "πŸ”–", keywords: ["bookmark", "link", "save", "reference"] }, { tagName: "folk-obs-note", label: "Obsidian Note", icon: "πŸ““", keywords: ["obsidian", "note", "vault", "knowledge"] }, // Module content hints (these create content in rApps, not canvas shapes) { tagName: "rcal-event", label: "Calendar Event", icon: "πŸ“…", keywords: ["event", "meeting", "schedule", "standup", "appointment"], moduleAction: { module: "rcal", contentType: "event" } }, { tagName: "rtasks-task", label: "Task", icon: "βœ…", keywords: ["task", "todo", "assign", "deadline", "backlog"], moduleAction: { module: "rtasks", contentType: "task" } }, { tagName: "rnotes-notebook", label: "Notebook", icon: "πŸ““", keywords: ["notebook", "journal", "documentation"], moduleAction: { module: "rnotes", contentType: "notebook" } }, { tagName: "rforum-thread", label: "Forum Thread", icon: "πŸ’¬", keywords: ["thread", "discussion", "forum", "topic"], moduleAction: { module: "rforum", contentType: "thread" } }, { tagName: "rvote-proposal", label: "Proposal", icon: "πŸ—³οΈ", keywords: ["proposal", "governance", "decision"], moduleAction: { module: "rvote", contentType: "proposal" } }, ]; /** * Given a user query, return matching tool hints (max 3). * Matches if any keyword appears in the query (case-insensitive). */ export function suggestTools(query: string): ToolHint[] { const q = query.toLowerCase(); const scored: { hint: ToolHint; score: number }[] = []; for (const hint of TOOL_HINTS) { let score = 0; for (const kw of hint.keywords) { if (q.includes(kw)) score += kw.length; // longer keyword match = higher relevance } if (score > 0) scored.push({ hint, score }); } return scored .sort((a, b) => b.score - a.score) .slice(0, 3) .map((s) => s.hint); }