evOo-local/packages/adapters/src/executor-tools.test.ts
Claude 044669edfc
Add a media library: owner folders that bots can search and import from
The deployment owner adds folders of photos and videos in the media settings. A per-folder
background job indexes them (relative path, kind, size, capture date, dimensions, duration),
re-indexes every six hours, and drops files that are gone. The owner's own runs get two tools:
search_media (words in folder and file names, kind, capture date range, newest first) and
import_media (copies one file into the conversation as an artifact). Files are never changed;
hidden entries and symlinks are skipped, and an import must resolve inside its folder.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy1md9QE1ayJbDCwJ4vAQs
2026-10-05 08:45:30 +00:00

132 lines
5.0 KiB
TypeScript

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"]);
});
});