Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
129 lines
4.6 KiB
TypeScript
129 lines
4.6 KiB
TypeScript
import type { ConnectorTool } from "@rakazo/adapter-kit";
|
|
import { agentConnectionTools, builtinAgentTools } from "./builtin-tools.js";
|
|
import { selectCloudAgentTools } from "./cloud-agent-tools-select.js";
|
|
import { COACH_TOOL_NAMES } from "./coach-tools.js";
|
|
import { selectMemoryTools } from "./memory-tools.js";
|
|
import { filterImageReturningComputerTools } from "./model-vision.js";
|
|
import {
|
|
filterBuiltinToolsForRun,
|
|
filterBuiltinToolsForThread,
|
|
withScheduleTargetBot,
|
|
} from "./schedule-tools.js";
|
|
|
|
/** Browser tools that require a graphical computer (Chrome). */
|
|
export const PAGE_BROWSER_TOOL_NAMES = new Set([
|
|
"browser_navigate",
|
|
"browser_snapshot",
|
|
"browser_act",
|
|
]);
|
|
|
|
/** Builtin tools only the user's main bot may use; every other bot's runs never see them. */
|
|
export const MAIN_ONLY_BUILTIN_TOOLS: ReadonlySet<string> = new Set<string>([
|
|
"delegate_task",
|
|
"notify_user",
|
|
"update_user_profile",
|
|
...COACH_TOOL_NAMES,
|
|
]);
|
|
|
|
/** Tools that write what the user's bots know about the user, so only the user may drive them. */
|
|
const USER_MODEL_TOOLS: ReadonlySet<string> = new Set<string>([
|
|
"update_user_profile",
|
|
"notify_user",
|
|
...COACH_TOOL_NAMES,
|
|
]);
|
|
|
|
const BUILTIN_TOOL_NAMES = [...builtinAgentTools, ...agentConnectionTools].map((tool) => tool.name);
|
|
|
|
/** The bot fields that decide which builtin tools its runs may use. */
|
|
export interface BuiltinToolPolicy {
|
|
kind: string;
|
|
restrictBuiltinTools: boolean;
|
|
allowedBuiltinTools: readonly string[];
|
|
}
|
|
|
|
/**
|
|
* Builtin tool names a bot's allowlist can choose from, in catalog order. Agent connection tools
|
|
* only ever reach chat-linked bots, so only those list them.
|
|
*/
|
|
export function builtinToolNamesForBot(bot: { kind: string; chatLinked: boolean }): string[] {
|
|
return [...builtinAgentTools, ...(bot.chatLinked ? agentConnectionTools : [])]
|
|
.map((tool) => tool.name)
|
|
.filter((name) => bot.kind === "main" || !MAIN_ONLY_BUILTIN_TOOLS.has(name));
|
|
}
|
|
|
|
/** Names that are not builtin tools; an allowlist must not carry typos or connector tools. */
|
|
export function unknownBuiltinToolNames(names: readonly string[]): string[] {
|
|
return names.filter((name) => !BUILTIN_TOOL_NAMES.includes(name));
|
|
}
|
|
|
|
/**
|
|
* Least privilege per bot: main-only tools stay with the main bot, a restricted bot keeps only
|
|
* its allowlist (empty means none), and the main bot may schedule for another bot.
|
|
*/
|
|
export function filterBuiltinToolsForBot(
|
|
tools: ConnectorTool[],
|
|
bot: BuiltinToolPolicy,
|
|
): ConnectorTool[] {
|
|
const main = bot.kind === "main";
|
|
const allowed = new Set(bot.allowedBuiltinTools);
|
|
return tools
|
|
.filter(
|
|
(tool) =>
|
|
(main || !MAIN_ONLY_BUILTIN_TOOLS.has(tool.name)) &&
|
|
(!bot.restrictBuiltinTools || allowed.has(tool.name)),
|
|
)
|
|
.map((tool) => (main && tool.name === "schedule_create" ? withScheduleTargetBot(tool) : tool));
|
|
}
|
|
|
|
export function filterPageBrowserTools<T extends { name: string }>(
|
|
tools: T[],
|
|
pageBrowserAllowed: boolean,
|
|
): T[] {
|
|
if (pageBrowserAllowed) return tools;
|
|
return tools.filter((tool) => !PAGE_BROWSER_TOOL_NAMES.has(tool.name));
|
|
}
|
|
|
|
export function selectBuiltinToolsForRun(options: {
|
|
graphicalToolsAllowed: boolean;
|
|
/** Page browser tools need a graphical computer (Chrome), not model vision. */
|
|
pageBrowserAllowed?: boolean;
|
|
groupId: string | null;
|
|
trigger: string;
|
|
semanticMemoryEnabled: boolean;
|
|
cloudAgentEnabled?: boolean;
|
|
messagingChannelRun: boolean;
|
|
/** Cross-owner agent connections only exist for chat-linked bots. */
|
|
agentConnectionsEnabled?: boolean;
|
|
/** Answering another owner's agent: what the run hears is not the user, so no profile writes. */
|
|
foreignAgentRun?: boolean;
|
|
bot: BuiltinToolPolicy;
|
|
}) {
|
|
const selected = selectCloudAgentTools(
|
|
selectMemoryTools(
|
|
filterBuiltinToolsForRun(
|
|
filterBuiltinToolsForThread(
|
|
filterPageBrowserTools(
|
|
filterImageReturningComputerTools(builtinAgentTools, options.graphicalToolsAllowed),
|
|
options.pageBrowserAllowed ?? options.graphicalToolsAllowed,
|
|
),
|
|
options.groupId,
|
|
),
|
|
options.trigger,
|
|
),
|
|
options.semanticMemoryEnabled,
|
|
),
|
|
Boolean(options.cloudAgentEnabled),
|
|
).filter(
|
|
(tool) =>
|
|
!(options.foreignAgentRun && USER_MODEL_TOOLS.has(tool.name)) &&
|
|
(!options.messagingChannelRun ||
|
|
(!["remember", "save_memory", "recall_memory", "forget_memory"].includes(tool.name) &&
|
|
!USER_MODEL_TOOLS.has(tool.name) &&
|
|
!tool.name.startsWith("scratchpad_"))),
|
|
);
|
|
return filterBuiltinToolsForBot(
|
|
options.agentConnectionsEnabled ? [...selected, ...agentConnectionTools] : selected,
|
|
options.bot,
|
|
);
|
|
}
|