rspace-online/lib/mi-tool-schema.ts

100 lines
8.1 KiB
TypeScript

/**
* 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);
}