import { describe, expect, it } from "vitest"; import { agentConnectionTools, builtinAgentTools } from "./builtin-tools.js"; import { builtinToolNamesForBot, filterBuiltinToolsForBot, MAIN_ONLY_BUILTIN_TOOLS, PERSONAL_AGENT_TOOLS, selectBuiltinToolsForRun, unknownBuiltinToolNames, } from "./executor-tools.js"; const unrestricted = { kind: "specialist", restrictBuiltinTools: false, allowedBuiltinTools: [] }; function select( bot: { kind: string; restrictBuiltinTools: boolean; allowedBuiltinTools: string[] }, options: { graphicalToolsAllowed?: boolean; agentConnectionsEnabled?: boolean; mediaLibraryEnabled?: boolean; foreignAgentRun?: boolean; messagingChannelRun?: boolean; } = {}, ) { return selectBuiltinToolsForRun({ graphicalToolsAllowed: options.graphicalToolsAllowed ?? true, groupId: null, trigger: "user", semanticMemoryEnabled: false, messagingChannelRun: options.messagingChannelRun ?? false, agentConnectionsEnabled: options.agentConnectionsEnabled, mediaLibraryEnabled: options.mediaLibraryEnabled, foreignAgentRun: options.foreignAgentRun, bot, }).map((tool) => tool.name); } /** Every builtin a specialist can get: the catalog without the main bot's own tools. */ const specialistToolNames = builtinAgentTools .map((tool) => tool.name) .filter((name) => !MAIN_ONLY_BUILTIN_TOOLS.has(name)); describe("builtin tools per bot", () => { it("adds agent connection tools only for chat-linked bots", () => { expect(select(unrestricted)).not.toContain("message_agent"); expect(select(unrestricted, { agentConnectionsEnabled: true })).toEqual( expect.arrayContaining(agentConnectionTools.map((tool) => tool.name)), ); }); it("offers the media library tools only to the user's own runs once a folder exists", () => { const library = ["search_media", "import_media"]; expect(select(unrestricted)).not.toEqual(expect.arrayContaining(["search_media"])); expect(select(unrestricted, { mediaLibraryEnabled: true })).toEqual( expect.arrayContaining(library), ); for (const run of [{ foreignAgentRun: true }, { messagingChannelRun: true }]) { const names = select(unrestricted, { mediaLibraryEnabled: true, ...run }); expect(names.filter((name) => library.includes(name))).toEqual([]); } }); it("applies the allowlist to agent connection tools too", () => { const bot = { kind: "specialist", restrictBuiltinTools: true, allowedBuiltinTools: ["message_agent", "read_file"], }; expect(select(bot, { agentConnectionsEnabled: true })).toEqual(["read_file", "message_agent"]); }); it("never brings back a tool the run itself withholds", () => { const bot = { kind: "specialist", restrictBuiltinTools: true, allowedBuiltinTools: ["computer_observe", "read_file"], }; expect(select(bot, { graphicalToolsAllowed: false })).toEqual(["read_file"]); }); it("ignores the allowlist while the restriction is off", () => { const bot = { ...unrestricted, allowedBuiltinTools: ["read_file"] }; expect(filterBuiltinToolsForBot(builtinAgentTools, bot).map((tool) => tool.name)).toEqual( specialistToolNames, ); }); it("lists main-only tools for the main bot alone", () => { expect([...MAIN_ONLY_BUILTIN_TOOLS].sort()).toEqual([ "delegate_task", "log_check_in", "notify_user", "update_goal", "update_habit", "update_user_profile", "write_daily_brief", ]); const specialist = builtinToolNamesForBot({ kind: "specialist", chatLinked: false }); const main = builtinToolNamesForBot({ kind: "main", chatLinked: false }); for (const name of MAIN_ONLY_BUILTIN_TOOLS) { expect(specialist).not.toContain(name); expect(main).toContain(name); } }); it("keeps the personal agent's tools from a project's main bot", () => { const main = { kind: "main", restrictBuiltinTools: false, allowedBuiltinTools: [] }; const personal = filterBuiltinToolsForBot(builtinAgentTools, { ...main, personalAgent: true }); const lead = filterBuiltinToolsForBot(builtinAgentTools, main).map((tool) => tool.name); expect(personal.map((tool) => tool.name)).toEqual( expect.arrayContaining([...PERSONAL_AGENT_TOOLS]), ); for (const name of PERSONAL_AGENT_TOOLS) expect(lead).not.toContain(name); expect(lead).toEqual(expect.arrayContaining(["delegate_task", "update_user_profile"])); }); it("lists agent connection tools only for chat-linked bots", () => { expect(builtinToolNamesForBot({ kind: "specialist", chatLinked: false })).toEqual( specialistToolNames, ); expect(builtinToolNamesForBot({ kind: "specialist", chatLinked: true })).toEqual([ ...specialistToolNames, ...agentConnectionTools.map((tool) => tool.name), ]); }); it("flags names that are not builtin tools", () => { expect( unknownBuiltinToolNames(["web_search", "message_agent", "web_serach", "mcp__notion__search"]), ).toEqual(["web_serach", "mcp__notion__search"]); }); });