From 3c6d178f4e5c515d183eb025ed7ded2dbb28d464 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 27 Apr 2026 13:27:13 +0100 Subject: [PATCH] docs: clarify malformed plugin tool guards --- src/agents/anthropic-transport-stream.ts | 2 ++ src/plugins/tools.ts | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/agents/anthropic-transport-stream.ts b/src/agents/anthropic-transport-stream.ts index 81e58698204..1e6e090addd 100644 --- a/src/agents/anthropic-transport-stream.ts +++ b/src/agents/anthropic-transport-stream.ts @@ -396,6 +396,8 @@ function convertAnthropicTools(tools: Context["tools"], isOAuthToken: boolean) { return []; } return tools.flatMap((tool) => { + // Main quarantine happens when plugin tools materialize; this keeps Anthropic + // safe for direct/custom tool arrays that bypass the plugin registry. const parameters = tool.parameters && typeof tool.parameters === "object" && !Array.isArray(tool.parameters) ? (tool.parameters as Record) diff --git a/src/plugins/tools.ts b/src/plugins/tools.ts index e774c3fef9f..37c5957e995 100644 --- a/src/plugins/tools.ts +++ b/src/plugins/tools.ts @@ -66,6 +66,7 @@ function readPluginToolName(tool: unknown): string { if (!isRecord(tool)) { return ""; } + // Optional-tool allowlists need a best-effort name before full shape validation. return typeof tool.name === "string" ? tool.name.trim() : ""; } @@ -189,6 +190,8 @@ export function resolvePluginTools(params: { } const nameSet = new Set(); for (const toolRaw of list) { + // Plugin factories run at request time and can return arbitrary values; isolate + // malformed tools here so one bad plugin tool cannot poison every provider. const malformedReason = describeMalformedPluginTool(toolRaw); if (malformedReason) { const message = `plugin tool is malformed (${entry.pluginId}): ${malformedReason}`;