import { describe, expect, it } from "vitest"; import { buildBotOverview, connectedAppsFacts, grantsSummary, setupSteps, soulLead, type OverviewFacts } from "./bot-overview.ts"; function baseFacts(overrides: Partial = {}): OverviewFacts { return { bot: { name: "Kiwi", title: "Tracker", description: "Files bugs.", soul: "", computer: "off", cloudBackend: undefined, cwd: undefined, autoApprove: false, composio: undefined, browser: undefined, chiefOfStaff: undefined, }, routines: [], runs: [], webhooks: [], skills: [], engine: null, connectedApps: { configured: false, authoritative: true, services: [] }, sectionPeers: 0, timeZone: "UTC", recent: [], ...overrides, }; } const WONT_ORDER = [ "Command approvals use Ask mode; saved permissions and provider rules still apply.", "Has no connected apps.", "Can't use a computer.", "Won't act on a schedule.", "Profile proposal cards require your approval.", ]; describe("buildBotOverview", () => { it("describes additional departments only for an authorized Chief", () => { const facts = baseFacts({ bot: { ...baseFacts().bot, chiefOfStaff: true, managedSections: ["Engineering", "Research"] }, engine: { agentsMcp: true }, sectionPeers: 3 }); expect(buildBotOverview(facts).reaches).toContain("Also in charge of these departments: Engineering, Research."); expect(buildBotOverview(facts).managedSections).toEqual(facts.bot.managedSections); facts.bot.chiefOfStaff = false; expect(buildBotOverview(facts).reaches.join(" ")).not.toContain("Engineering"); }); it("says a bot can talk to every other bot", () => { const open = baseFacts({ bot: baseFacts().bot, engine: { agentsMcp: true }, sectionPeers: 3 }); expect(buildBotOverview(open).reaches).toContain("Can talk to all 3 other bots, in any department."); expect(buildBotOverview({ ...open, sectionPeers: 1 }).reaches).toContain("Can talk to the other bot."); }); it("yields all five wont lines in order and no does lines for a bot on Ask", () => { const overview = buildBotOverview(baseFacts({ bot: { ...baseFacts().bot, approvalMode: "ask" } })); expect(overview.wont).toEqual(WONT_ORDER); expect(overview.does).toEqual([]); }); it("describes a fresh bot at the default level, Full access", () => { expect(buildBotOverview(baseFacts()).wont).toEqual(WONT_ORDER.slice(1, -1)); }); it("drops the first wont line when autoApprove is on", () => { const overview = buildBotOverview(baseFacts({ bot: { ...baseFacts().bot, autoApprove: true } })); expect(overview.wont).toEqual(WONT_ORDER.slice(1)); }); it("uses the effective approval level rather than the legacy Auto bit", () => { const bot = { ...baseFacts().bot, approvalMode: "full" as const, autoApprove: false }; expect(buildBotOverview(baseFacts({ bot })).wont).not.toContain(WONT_ORDER[0]); expect(buildBotOverview(baseFacts({ bot: { ...bot, approvalMode: "custom" } })).wont) .toContain("Command approvals follow the provider's custom configuration."); }); it("does not promise profile approvals in Full Access", () => { const bot = { ...baseFacts().bot, approvalMode: "full" as const, autoApprove: false }; expect(buildBotOverview(baseFacts({ bot })).wont).not.toContain("Profile proposal cards require your approval."); for (const approvalMode of ["ask", "custom"] as const) { expect(buildBotOverview(baseFacts({ bot: { ...bot, approvalMode, autoApprove: true } })).wont).toContain("Profile proposal cards require your approval."); } }); it("does not advertise a browser disabled globally or unsupported by the engine", () => { const facts = baseFacts({ bot: { ...baseFacts().bot, computer: "browser" }, browserEnabled: true, engine: { browserMcp: false } }); expect(buildBotOverview(facts).reaches).not.toContain("Has the built-in browser."); facts.engine = { browserMcp: true }; facts.browserEnabled = false; expect(buildBotOverview(facts).reaches).not.toContain("Has the built-in browser."); facts.browserEnabled = true; expect(buildBotOverview(facts).reaches).toContain("Has the built-in browser."); }); it("renders an enabled interval routine with its last completed run", () => { const facts = baseFacts({ routines: [ { id: "r1", name: "Triage Discord", enabled: true, schedule: { type: "interval", everyMinutes: 5, anchorAt: 1_000 }, nextRunAt: 2_000, }, ], runs: [ { routineId: "r1", status: "completed", finishedAt: 1_500, scheduledFor: 1_000 }, ], }); const overview = buildBotOverview(facts); expect(overview.does).toHaveLength(1); expect(overview.does[0]).toMatch(/^Every 5 minutes: Triage Discord\./); expect(overview.does[0]).not.toContain("UTC"); expect(overview.does[0]).not.toContain("anchored"); expect(overview.does[0]).toContain("Last run completed at"); expect(overview.does[0]).toContain("Next run"); expect(overview.wont).not.toContain("Won't act on a schedule."); expect(overview.doesRoutines).toEqual([{ name: "Triage Discord", schedule: { type: "interval", everyMinutes: 5, anchorAt: 1_000 }, nextRunAt: 2_000, lastRun: { status: "completed", at: 1_500 } }]); }); it("renders a paused routine as Paused: name", () => { const facts = baseFacts({ routines: [ { id: "r2", name: "Nightly Backup", enabled: false, schedule: { type: "daily", time: "09:00", weekdays: [1] }, nextRunAt: null, }, ], }); const overview = buildBotOverview(facts); expect(overview.does).toEqual(["Paused: Nightly Backup."]); expect(overview.doesRoutines).toEqual([{ name: "Nightly Backup", paused: true, schedule: { type: "daily", time: "09:00", weekdays: [1] } }]); expect(overview.wont).toContain("Won't act on a schedule."); }); it("renders enabled skills and webhooks as their own does lines", () => { const facts = baseFacts({ skills: [ { name: "triage", description: "Triage incoming bug reports", enabled: true }, { name: "disabled-skill", description: "Should not appear", enabled: false }, ], webhooks: [ { name: "Linear", enabled: true }, { name: "Disabled hook", enabled: false }, ], }); const overview = buildBotOverview(facts); expect(overview.does).toEqual([ "Knows how to triage incoming bug reports.", "Listens for “Linear” webhooks.", ]); }); it("shows two connected services in reaches", () => { const facts = baseFacts({ bot: { ...baseFacts().bot, composio: true, computer: "local" }, engine: { composioMcp: true }, connectedApps: { configured: true, authoritative: true, services: ["gmail", "linear"] }, }); const overview = buildBotOverview(facts); expect(overview.reaches).toContain("Can use 2 connected apps: gmail, linear."); expect(overview.wont).not.toContain("Has no connected apps."); }); it("reports connected apps could not be checked when unauthoritative, without also claiming none connected", () => { const facts = baseFacts({ bot: { ...baseFacts().bot, composio: true, computer: "local" }, engine: { composioMcp: true }, connectedApps: { configured: true, authoritative: false, services: [] }, }); const overview = buildBotOverview(facts); expect(overview.reaches).toContain("Connected apps could not be checked."); expect(overview.wont).not.toContain("Has no connected apps."); expect(overview.reaches.some((line) => line.startsWith("Can use"))).toBe(false); }); it("states 'Has no connected apps.' when apps are off for the bot, even if the inventory is unverifiable", () => { // Apps off is a definite negative that needs no inventory — saying // "could not be checked" here would imply the bot might have apps. const facts = baseFacts({ bot: { ...baseFacts().bot, composio: false, computer: "local" }, engine: { composioMcp: true }, connectedApps: { configured: true, authoritative: false, services: [] }, }); const overview = buildBotOverview(facts); expect(overview.wont).toContain("Has no connected apps."); expect(overview.reaches).not.toContain("Connected apps could not be checked."); }); it("stays silent about apps in reaches when the engine cannot mount them", () => { const facts = baseFacts({ bot: { ...baseFacts().bot, composio: true, computer: "local" }, engine: { composioMcp: false }, connectedApps: { configured: true, authoritative: false, services: ["gmail"] }, }); const overview = buildBotOverview(facts); expect(overview.wont).toContain("Has no connected apps."); expect(overview.reaches.some((line) => line.includes("connected app"))).toBe(false); }); it("uses the singular for one connected app", () => { const facts = baseFacts({ bot: { ...baseFacts().bot, composio: true, computer: "local" }, engine: { composioMcp: true }, connectedApps: { configured: true, authoritative: true, services: ["gmail"] }, }); expect(buildBotOverview(facts).reaches).toContain("Can use 1 connected app: gmail."); }); it("writes daily and once schedules as prose", () => { const overview = buildBotOverview(baseFacts({ routines: [ { id: "a", name: "Standup", enabled: true, schedule: { type: "daily", time: "09:30", weekdays: [1, 2, 3, 4, 5] }, nextRunAt: null }, { id: "b", name: "Digest", enabled: true, schedule: { type: "daily", time: "18:00", weekdays: [0, 1, 2, 3, 4, 5, 6] }, nextRunAt: null }, { id: "c", name: "Review", enabled: true, schedule: { type: "daily", time: "08:00", weekdays: [3] }, nextRunAt: null }, { id: "d", name: "Launch", enabled: true, schedule: { type: "once", at: Date.UTC(2026, 8, 5, 12) }, nextRunAt: null }, { id: "e", name: "Hourly", enabled: true, schedule: { type: "interval", everyMinutes: 60 }, nextRunAt: null }, ], })); expect(overview.does).toEqual([ "Every weekday at 9:30 AM: Standup.", "Every day at 6:00 PM: Digest.", "Weekly on Wednesday at 8:00 AM: Review.", "Once on September 5 at 12:00 PM: Launch.", "Every hour: Hourly.", ]); }); it("picks a computer automatically when the computer is unset", () => { const facts = baseFacts({ bot: { ...baseFacts().bot, computer: undefined } }); const overview = buildBotOverview(facts); expect(overview.reaches).toContain("Computer preference: Auto; availability is checked when a task starts."); expect(overview.wont).not.toContain("Can't use a computer."); expect(overview.wont).not.toContain("Won't contact other bots without asking."); }); it("says a Cloud home cannot use this computer or a Local VM, and changes nothing elsewhere", () => { const reach = (computer: OverviewFacts["bot"]["computer"], cloudHome?: boolean) => buildBotOverview(baseFacts({ bot: { ...baseFacts().bot, computer }, ...(cloudHome === undefined ? {} : { cloudHome }) })).reaches[0]; expect(reach("local", true)).toBe("Computer preference: this computer, which isn't available on My Cloud."); expect(reach("vm", true)).toBe("Computer preference: Local VM, which isn't available on My Cloud."); expect(reach("cloud", true)).toBe("Computer preference: cloud computer."); expect(reach("browser", true)).toBe("Computer preference: browser only."); expect(reach(undefined, true)).toBe("Computer preference: Auto; availability is checked when a task starts."); for (const cloudHome of [undefined, false]) { expect(reach("local", cloudHome)).toBe("Computer preference: this computer."); expect(reach("vm", cloudHome)).toBe("Computer preference: Local VM."); } }); }); describe("soulLead", () => { it("cuts at the first blank line", () => { expect(soulLead("First paragraph.\n\nSecond paragraph.")).toBe("First paragraph."); }); it("cuts at 240 characters", () => { const long = "A".repeat(300); const result = soulLead(long); expect(result).toBe(`${"A".repeat(240)}…`); }); it("returns an empty string for an unset soul", () => { expect(soulLead(undefined)).toBe(""); }); }); describe("connectedAppsFacts", () => { it("lists the connected slugs when the inventory reads cleanly", async () => { const facts = await connectedAppsFacts(true, "configured", async () => ({ gmail: { connected: true }, linear: { connected: false }, })); expect(facts).toEqual({ configured: true, authoritative: true, services: ["gmail"] }); }); it("marks the inventory unverified instead of throwing when the read fails", async () => { const facts = await connectedAppsFacts(true, "configured", async () => { throw new Error("Connected apps: HTTP 502"); }); expect(facts).toEqual({ configured: true, authoritative: false, services: [] }); }); it("never reads when the connector is unconfigured or the store was unreadable", async () => { let reads = 0; const read = async () => { reads += 1; return {}; }; expect(await connectedAppsFacts(false, "unconfigured", read)).toEqual({ configured: false, authoritative: true, services: [] }); expect(await connectedAppsFacts(false, "unreadable", read)).toEqual({ configured: false, authoritative: false, services: [] }); expect(reads).toBe(0); }); }); describe("grantsSummary", () => { it("stays off the wire for a bot with no grants record", () => { expect(grantsSummary(undefined)).toBeUndefined(); expect(buildBotOverview(baseFacts()).grants).toBeUndefined(); }); it("summarizes wildcards, exact lists and an explicit no-tools record", () => { const grants = grantsSummary({ slack: { tools: "*" }, gmail: { tools: ["GMAIL_SEND_EMAIL", "GMAIL_FETCH_EMAILS"] }, }); expect(grants).toEqual([ { slug: "gmail", level: "partial", toolCount: 2 }, { slug: "slack", level: "all", toolCount: 0 }, ]); // {} is the explicit no-tools record: an empty list, not an absent one expect(grantsSummary({})).toEqual([]); expect(buildBotOverview(baseFacts({ bot: { ...baseFacts().bot, connectorTools: {} } })).grants).toEqual([]); }); it("rides along in the built overview for a partial grant set", () => { const connectorTools = { gmail: { tools: ["GMAIL_SEND_EMAIL"] } }; const overview = buildBotOverview(baseFacts({ bot: { ...baseFacts().bot, connectorTools } })); expect(overview.grants).toEqual([{ slug: "gmail", level: "partial", toolCount: 1 }]); }); }); describe("setupSteps", () => { it("lists optional setup ideas without inspecting conversation history", () => { const steps = setupSteps(baseFacts({ bot: { ...baseFacts().bot, name: "New bot", title: "", description: "" } })); expect(steps.map((step) => [step.id, step.done])).toEqual([ ["identity", false], ["soul", false], ["folder", false], ["schedule", false], ]); expect(steps.find((step) => step.id === "apps")).toBeUndefined(); expect(steps.every((step) => step.section)).toBe(true); }); it("marks steps done from the same facts the sentences use", () => { const facts = baseFacts({ bot: { ...baseFacts().bot, name: "Kiwi", title: "Tracker", soul: "Be brief.", cwd: "/work", composio: true }, engine: { composioMcp: true }, connectedApps: { configured: true, authoritative: true, services: ["gmail"] }, routines: [{ id: "r1", name: "Digest", enabled: true, schedule: { type: "daily", time: "09:00", weekdays: [1, 2, 3, 4, 5] }, nextRunAt: null }], }); expect(setupSteps(facts).every((step) => step.done)).toBe(true); expect(setupSteps(facts).map((step) => step.id)).toContain("apps"); expect(buildBotOverview(facts).setup).toEqual(setupSteps(facts)); }); it("does not count an unverified app inventory or a paused routine as done", () => { const facts = baseFacts({ bot: { ...baseFacts().bot, composio: true }, engine: { composioMcp: true }, connectedApps: { configured: true, authoritative: false, services: ["gmail"] }, routines: [{ id: "r1", name: "Digest", enabled: false, schedule: { type: "daily", time: "09:00", weekdays: [1] }, nextRunAt: null }], }); const byId = Object.fromEntries(setupSteps(facts).map((step) => [step.id, step.done])); expect(byId.apps).toBe(false); expect(byId.schedule).toBe(false); }); });