390 lines
20 KiB
TypeScript
390 lines
20 KiB
TypeScript
/**
|
|
* MI Data Queries — dispatches content queries to module-specific readers.
|
|
*
|
|
* Used by the agentic loop to fetch module data server-side and feed
|
|
* results back into the LLM context.
|
|
*/
|
|
|
|
import { getUpcomingEventsForMI } from "../modules/rcal/mod";
|
|
import { getRecentVaultNotesForMI } from "../modules/rnotes/mod";
|
|
import { getRecentTasksForMI } from "../modules/rtasks/mod";
|
|
import { getRecentCampaignsForMI } from "../modules/rsocials/mod";
|
|
import { getRecentContactsForMI } from "../modules/rnetwork/mod";
|
|
import { getRecentThreadsForMI } from "../modules/rinbox/mod";
|
|
import { getRecentCommitmentsForMI } from "../modules/rtime/mod";
|
|
import { getRecentFilesForMI } from "../modules/rfiles/mod";
|
|
import { getUpcomingRemindersForMI } from "../modules/rschedule/mod";
|
|
import { getMapPinsForMI } from "../modules/rmaps/mod";
|
|
import { getRecentMeetingsForMI } from "../modules/rmeets/mod";
|
|
import { getRecentVideosForMI } from "../modules/rtube/mod";
|
|
import { getRecentMessagesForMI } from "../modules/rchats/mod";
|
|
import { getRecentPublicationsForMI } from "../modules/rpubs/mod";
|
|
import { getRecentDesignsForMI } from "../modules/rswag/mod";
|
|
import { getRecentSheetsForMI } from "../modules/rsheets/mod";
|
|
import { getRecentDocsForMI } from "../modules/rdocs/mod";
|
|
import { getRecentSessionsForMI } from "../modules/rdesign/mod";
|
|
import { getSharedAlbumsForMI } from "../modules/rphotos/mod";
|
|
import { getRecentFlowsForMI } from "../modules/rflows/mod";
|
|
import { getRecentIntentsForMI } from "../modules/rexchange/mod";
|
|
import { getRecentOrdersForMI } from "../modules/rcart/mod";
|
|
import { getActiveProposalsForMI } from "../modules/rvote/mod";
|
|
import { getRecentBooksForMI } from "../modules/rbooks/mod";
|
|
import { getRecentSplatsForMI } from "../modules/rsplat/mod";
|
|
import { getRecentTripsForMI } from "../modules/rtrips/mod";
|
|
import { getActiveListingsForMI } from "../modules/rbnb/mod";
|
|
import { getActiveVehiclesForMI } from "../modules/rvnb/mod";
|
|
import { getForumInstancesForMI } from "../modules/rforum/mod";
|
|
import { getRecentChoiceSessionsForMI } from "../modules/rchoices/mod";
|
|
import { getActivePromptsForMI } from "../modules/crowdsurf/mod";
|
|
import { getGovShapesForMI } from "../modules/rgov/mod";
|
|
import { getCrdtTokensForMI } from "../modules/rwallet/mod";
|
|
import { getCanvasSummaryForMI } from "../modules/rspace/mod";
|
|
import { getDataSummaryForMI } from "../modules/rdata/mod";
|
|
|
|
export interface MiQueryResult {
|
|
ok: boolean;
|
|
module: string;
|
|
queryType: string;
|
|
data: any;
|
|
summary: string;
|
|
}
|
|
|
|
/**
|
|
* Query module content by type. Returns structured data + a text summary
|
|
* the LLM can consume.
|
|
*/
|
|
export function queryModuleContent(
|
|
space: string,
|
|
module: string,
|
|
queryType: "recent" | "summary" | "count",
|
|
limit = 5,
|
|
): MiQueryResult {
|
|
switch (module) {
|
|
case "rnotes": {
|
|
const notes = getRecentVaultNotesForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: notes.length }, summary: `${notes.length} vault notes found.` };
|
|
}
|
|
const lines = notes.map((n) => `- "${n.title}" in ${n.vaultName} (${n.path})${n.tags.length ? ` [${n.tags.join(", ")}]` : ""}`);
|
|
return { ok: true, module, queryType, data: notes, summary: lines.length ? `Vault notes:\n${lines.join("\n")}` : "No vault notes found." };
|
|
}
|
|
|
|
case "rtasks": {
|
|
const tasks = getRecentTasksForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: tasks.length }, summary: `${tasks.length} open tasks found.` };
|
|
}
|
|
const lines = tasks.map((t) => `- "${t.title}" [${t.status}]${t.priority ? ` (${t.priority})` : ""}${t.description ? `: ${t.description.slice(0, 80)}` : ""}`);
|
|
return { ok: true, module, queryType, data: tasks, summary: lines.length ? `Open tasks:\n${lines.join("\n")}` : "No open tasks." };
|
|
}
|
|
|
|
case "rcal": {
|
|
const events = getUpcomingEventsForMI(space, 14, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: events.length }, summary: `${events.length} upcoming events.` };
|
|
}
|
|
const lines = events.map((e) => {
|
|
const date = e.allDay ? e.start.split("T")[0] : e.start;
|
|
let line = `- ${date}: ${e.title}`;
|
|
if (e.location) line += ` (${e.location})`;
|
|
return line;
|
|
});
|
|
return { ok: true, module, queryType, data: events, summary: lines.length ? `Upcoming events:\n${lines.join("\n")}` : "No upcoming events." };
|
|
}
|
|
|
|
case "rsocials": {
|
|
const campaigns = getRecentCampaignsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: campaigns.length }, summary: `${campaigns.length} campaigns found.` };
|
|
}
|
|
const lines = campaigns.map((c) => `- "${c.title}" (${c.platforms.join(", ")}, ${c.postCount} posts)`);
|
|
return { ok: true, module, queryType, data: campaigns, summary: lines.length ? `Recent campaigns:\n${lines.join("\n")}` : "No campaigns found." };
|
|
}
|
|
|
|
case "rnetwork": {
|
|
const contacts = getRecentContactsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: contacts.length }, summary: `${contacts.length} contacts found.` };
|
|
}
|
|
const lines = contacts.map((c) => `- ${c.name} (${c.role})${c.tags.length ? ` [${c.tags.join(", ")}]` : ""}`);
|
|
return { ok: true, module, queryType, data: contacts, summary: lines.length ? `Contacts:\n${lines.join("\n")}` : "No contacts found." };
|
|
}
|
|
|
|
case "rinbox": {
|
|
const threads = getRecentThreadsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: threads.length }, summary: `${threads.length} email threads found.` };
|
|
}
|
|
const lines = threads.map((t) => `- "${t.subject}" from ${t.fromAddress || "unknown"} [${t.status}]${t.isRead ? "" : " (unread)"}`);
|
|
return { ok: true, module, queryType, data: threads, summary: lines.length ? `Recent threads:\n${lines.join("\n")}` : "No email threads." };
|
|
}
|
|
|
|
case "rtime": {
|
|
const commitments = getRecentCommitmentsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: commitments.length }, summary: `${commitments.length} active commitments.` };
|
|
}
|
|
const lines = commitments.map((c) => `- ${c.memberName}: ${c.hours}h ${c.skill} — ${c.desc.slice(0, 80)}`);
|
|
return { ok: true, module, queryType, data: commitments, summary: lines.length ? `Active commitments:\n${lines.join("\n")}` : "No active commitments." };
|
|
}
|
|
|
|
case "rfiles": {
|
|
const files = getRecentFilesForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: files.length }, summary: `${files.length} files found.` };
|
|
}
|
|
const lines = files.map((f) => `- ${f.title || f.originalFilename} (${f.mimeType || "unknown"}, ${Math.round(f.fileSize / 1024)}KB)`);
|
|
return { ok: true, module, queryType, data: files, summary: lines.length ? `Recent files:\n${lines.join("\n")}` : "No files found." };
|
|
}
|
|
|
|
case "rschedule": {
|
|
const reminders = getUpcomingRemindersForMI(space, 14, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: reminders.length }, summary: `${reminders.length} upcoming reminders.` };
|
|
}
|
|
const lines = reminders.map((r) => {
|
|
const date = new Date(r.remindAt).toISOString().split("T")[0];
|
|
let line = `- ${date}: ${r.title}`;
|
|
if (r.sourceModule) line += ` (from ${r.sourceModule})`;
|
|
return line;
|
|
});
|
|
return { ok: true, module, queryType, data: reminders, summary: lines.length ? `Upcoming reminders:\n${lines.join("\n")}` : "No upcoming reminders." };
|
|
}
|
|
|
|
case "rmaps": {
|
|
const pins = getMapPinsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: pins.length }, summary: `${pins.length} map pins found.` };
|
|
}
|
|
const lines = pins.map((p) => `- "${p.label}" (${p.type}) at ${p.lat.toFixed(4)}, ${p.lng.toFixed(4)}`);
|
|
return { ok: true, module, queryType, data: pins, summary: lines.length ? `Map pins:\n${lines.join("\n")}` : "No map pins." };
|
|
}
|
|
|
|
case "rmeets": {
|
|
const meetings = getRecentMeetingsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: meetings.length }, summary: `${meetings.length} meetings found.` };
|
|
}
|
|
const lines = meetings.map((m) => `- "${m.title}" (${m.participantCount} participants, ${new Date(m.scheduledAt).toLocaleDateString()})`);
|
|
return { ok: true, module, queryType, data: meetings, summary: lines.length ? `Recent meetings:\n${lines.join("\n")}` : "No meetings found." };
|
|
}
|
|
|
|
case "rtube": {
|
|
const videos = getRecentVideosForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: videos.length }, summary: `${videos.length} playlists found.` };
|
|
}
|
|
const lines = videos.map((v) => `- "${v.name}" (${v.entryCount} entries)`);
|
|
return { ok: true, module, queryType, data: videos, summary: lines.length ? `Playlists:\n${lines.join("\n")}` : "No playlists found." };
|
|
}
|
|
|
|
case "rchats": {
|
|
const msgs = getRecentMessagesForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: msgs.length }, summary: `${msgs.length} recent messages.` };
|
|
}
|
|
const lines = msgs.map((m) => `- [${m.channel}] ${m.author}: ${m.content.slice(0, 100)}`);
|
|
return { ok: true, module, queryType, data: msgs, summary: lines.length ? `Recent chats:\n${lines.join("\n")}` : "No chat messages." };
|
|
}
|
|
|
|
case "rpubs": {
|
|
const pubs = getRecentPublicationsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: pubs.length }, summary: `${pubs.length} publications found.` };
|
|
}
|
|
const lines = pubs.map((p) => `- "${p.title}" by ${p.author} (${p.format})`);
|
|
return { ok: true, module, queryType, data: pubs, summary: lines.length ? `Publications:\n${lines.join("\n")}` : "No publications found." };
|
|
}
|
|
|
|
case "rswag": {
|
|
const designs = getRecentDesignsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: designs.length }, summary: `${designs.length} designs found.` };
|
|
}
|
|
const lines = designs.map((d) => `- "${d.title}" (${d.productType}, ${d.status})`);
|
|
return { ok: true, module, queryType, data: designs, summary: lines.length ? `Store designs:\n${lines.join("\n")}` : "No designs found." };
|
|
}
|
|
|
|
case "rsheets": {
|
|
const sheets = getRecentSheetsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: sheets.length }, summary: `${sheets.length} spreadsheets found.` };
|
|
}
|
|
const lines = sheets.map((s) => `- "${s.name}" (${s.cellCount} cells, updated ${new Date(s.updatedAt).toLocaleDateString()})`);
|
|
return { ok: true, module, queryType, data: sheets, summary: lines.length ? `Spreadsheets:\n${lines.join("\n")}` : "No spreadsheets found." };
|
|
}
|
|
|
|
case "rdocs": {
|
|
const docs = getRecentDocsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: docs.length }, summary: `${docs.length} docs found.` };
|
|
}
|
|
const lines = docs.map((n) => `- "${n.title}" (${n.type}, updated ${new Date(n.updatedAt).toLocaleDateString()})${n.tags.length ? ` [${n.tags.join(", ")}]` : ""}: ${n.contentPlain.slice(0, 100)}...`);
|
|
return { ok: true, module, queryType, data: docs, summary: lines.length ? `Recent docs:\n${lines.join("\n")}` : "No docs found." };
|
|
}
|
|
|
|
case "rdesign": {
|
|
const sessions = getRecentSessionsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: sessions.length }, summary: `${sessions.length} design sessions found.` };
|
|
}
|
|
const lines = sessions.map((s) => `- "${s.title}" (${s.pageCount} pages, ${s.frameCount} frames)`);
|
|
return { ok: true, module, queryType, data: sessions, summary: lines.length ? `Design sessions:\n${lines.join("\n")}` : "No design sessions." };
|
|
}
|
|
|
|
case "rphotos": {
|
|
const albums = getSharedAlbumsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: albums.length }, summary: `${albums.length} shared albums found.` };
|
|
}
|
|
const lines = albums.map((a) => `- "${a.name}" (shared ${new Date(a.sharedAt).toLocaleDateString()})`);
|
|
return { ok: true, module, queryType, data: albums, summary: lines.length ? `Shared albums:\n${lines.join("\n")}` : "No shared albums." };
|
|
}
|
|
|
|
case "rflows": {
|
|
const flows = getRecentFlowsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: flows.length }, summary: `${flows.length} flows found.` };
|
|
}
|
|
const lines = flows.map((f) => `- "${f.name}" (${f.nodeCount} nodes)`);
|
|
return { ok: true, module, queryType, data: flows, summary: lines.length ? `Flows:\n${lines.join("\n")}` : "No flows found." };
|
|
}
|
|
|
|
case "rexchange": {
|
|
const intents = getRecentIntentsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: intents.length }, summary: `${intents.length} exchange intents.` };
|
|
}
|
|
const lines = intents.map((i) => `- ${i.side} ${i.tokenId} [${i.status}]`);
|
|
return { ok: true, module, queryType, data: intents, summary: lines.length ? `Exchange intents:\n${lines.join("\n")}` : "No exchange intents." };
|
|
}
|
|
|
|
case "rcart": {
|
|
const orders = getRecentOrdersForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: orders.length }, summary: `${orders.length} orders found.` };
|
|
}
|
|
const lines = orders.map((o) => `- "${o.title}" [${o.status}] ($${o.totalPrice})`);
|
|
return { ok: true, module, queryType, data: orders, summary: lines.length ? `Recent orders:\n${lines.join("\n")}` : "No orders found." };
|
|
}
|
|
|
|
case "rvote": {
|
|
const proposals = getActiveProposalsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: proposals.length }, summary: `${proposals.length} proposals found.` };
|
|
}
|
|
const lines = proposals.map((p) => `- "${p.title}" [${p.status}] (score: ${p.score}, ${p.voteCount} votes)`);
|
|
return { ok: true, module, queryType, data: proposals, summary: lines.length ? `Proposals:\n${lines.join("\n")}` : "No proposals found." };
|
|
}
|
|
|
|
case "rbooks": {
|
|
const books = getRecentBooksForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: books.length }, summary: `${books.length} books found.` };
|
|
}
|
|
const lines = books.map((b) => `- "${b.title}" by ${b.author} (${b.pageCount} pages)`);
|
|
return { ok: true, module, queryType, data: books, summary: lines.length ? `Books:\n${lines.join("\n")}` : "No books found." };
|
|
}
|
|
|
|
case "rsplat": {
|
|
const splats = getRecentSplatsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: splats.length }, summary: `${splats.length} 3D scenes found.` };
|
|
}
|
|
const lines = splats.map((s) => `- "${s.title}" (${s.format}, ${s.status})`);
|
|
return { ok: true, module, queryType, data: splats, summary: lines.length ? `3D scenes:\n${lines.join("\n")}` : "No 3D scenes found." };
|
|
}
|
|
|
|
case "rtrips": {
|
|
const trips = getRecentTripsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: trips.length }, summary: `${trips.length} trips found.` };
|
|
}
|
|
const lines = trips.map((t) => `- "${t.title}" [${t.status}] (${t.destinationCount} destinations${t.startDate ? `, starts ${t.startDate}` : ""})`);
|
|
return { ok: true, module, queryType, data: trips, summary: lines.length ? `Trips:\n${lines.join("\n")}` : "No trips found." };
|
|
}
|
|
|
|
case "rbnb": {
|
|
const listings = getActiveListingsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: listings.length }, summary: `${listings.length} active listings.` };
|
|
}
|
|
const lines = listings.map((l) => `- "${l.title}" (${l.type}, ${l.locationName || "unknown location"}, ${l.economy})`);
|
|
return { ok: true, module, queryType, data: listings, summary: lines.length ? `Listings:\n${lines.join("\n")}` : "No active listings." };
|
|
}
|
|
|
|
case "rvnb": {
|
|
const vehicles = getActiveVehiclesForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: vehicles.length }, summary: `${vehicles.length} active vehicles.` };
|
|
}
|
|
const lines = vehicles.map((v) => `- "${v.title}" (${v.type}, ${v.locationName || "unknown location"}, ${v.economy})`);
|
|
return { ok: true, module, queryType, data: vehicles, summary: lines.length ? `Vehicles:\n${lines.join("\n")}` : "No active vehicles." };
|
|
}
|
|
|
|
case "rforum": {
|
|
const instances = getForumInstancesForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: instances.length }, summary: `${instances.length} forum instances.` };
|
|
}
|
|
const lines = instances.map((i) => `- "${i.name}" (${i.domain || "no domain"}) [${i.status}]`);
|
|
return { ok: true, module, queryType, data: instances, summary: lines.length ? `Forum instances:\n${lines.join("\n")}` : "No forum instances." };
|
|
}
|
|
|
|
case "rchoices": {
|
|
const sessions = getRecentChoiceSessionsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: sessions.length }, summary: `${sessions.length} choice sessions.` };
|
|
}
|
|
const lines = sessions.map((s) => `- "${s.title}" (${s.type}, ${s.optionCount} options${s.closed ? ", closed" : ""})`);
|
|
return { ok: true, module, queryType, data: sessions, summary: lines.length ? `Choice sessions:\n${lines.join("\n")}` : "No choice sessions." };
|
|
}
|
|
|
|
case "crowdsurf": {
|
|
const prompts = getActivePromptsForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: prompts.length }, summary: `${prompts.length} crowdsurf prompts.` };
|
|
}
|
|
const lines = prompts.map((p) => `- "${p.text.slice(0, 80)}" (${p.swipeCount}/${p.threshold} swipes${p.triggered ? ", triggered" : ""})`);
|
|
return { ok: true, module, queryType, data: prompts, summary: lines.length ? `Crowdsurf prompts:\n${lines.join("\n")}` : "No crowdsurf prompts." };
|
|
}
|
|
|
|
case "rgov": {
|
|
const shapes = getGovShapesForMI(space, limit);
|
|
if (queryType === "count") {
|
|
const total = shapes.reduce((sum, s) => sum + s.count, 0);
|
|
return { ok: true, module, queryType, data: { count: total }, summary: `${total} governance shapes.` };
|
|
}
|
|
const lines = shapes.map((s) => `- ${s.type}: ${s.count}`);
|
|
return { ok: true, module, queryType, data: shapes, summary: lines.length ? `Governance shapes:\n${lines.join("\n")}` : "No governance shapes." };
|
|
}
|
|
|
|
case "rwallet": {
|
|
const tokens = getCrdtTokensForMI(space, limit);
|
|
if (queryType === "count") {
|
|
return { ok: true, module, queryType, data: { count: tokens.length }, summary: `${tokens.length} CRDT tokens.` };
|
|
}
|
|
const lines = tokens.map((t) => `- ${t.symbol} (${t.name}): supply ${t.totalSupply}`);
|
|
return { ok: true, module, queryType, data: tokens, summary: lines.length ? `CRDT tokens:\n${lines.join("\n")}` : "No CRDT tokens." };
|
|
}
|
|
|
|
case "rspace": {
|
|
const summary = getCanvasSummaryForMI(space, limit);
|
|
if (!summary.length || !summary[0].totalShapes) {
|
|
return { ok: true, module, queryType, data: summary, summary: "Empty canvas." };
|
|
}
|
|
const s = summary[0];
|
|
const lines = s.typeBreakdown.map((t) => `- ${t.type}: ${t.count}`);
|
|
return { ok: true, module, queryType, data: summary, summary: `Canvas: ${s.totalShapes} shapes\n${lines.join("\n")}` };
|
|
}
|
|
|
|
case "rdata": {
|
|
const data = getDataSummaryForMI(space, limit);
|
|
return { ok: true, module, queryType, data, summary: "rData proxies Umami analytics — use the dashboard for stats." };
|
|
}
|
|
|
|
default:
|
|
return { ok: false, module, queryType, data: null, summary: `Module "${module}" does not support content queries.` };
|
|
}
|
|
}
|