diff --git a/src/plugins/tools.optional.test.ts b/src/plugins/tools.optional.test.ts index d78da884b3f..8c848323989 100644 --- a/src/plugins/tools.optional.test.ts +++ b/src/plugins/tools.optional.test.ts @@ -2061,6 +2061,39 @@ describe("resolvePluginTools optional tools", () => { expect(factory).toHaveBeenCalledTimes(2); }); + it("executes cached healthy tools when a runtime sibling is malformed", async () => { + const factory = vi.fn(() => [ + createMalformedTool("fuzz_move_angles"), + { + ...makeTool("mockplugin_status"), + async execute() { + return { content: [{ type: "text", text: "mock-status-ok" }] }; + }, + }, + ]); + setRegistry([ + { + pluginId: "fuzzplugin", + optional: false, + source: "/tmp/fuzzplugin.js", + names: ["mockplugin_status"], + factory, + }, + ]); + + const first = resolvePluginTools(createResolveToolsParams()); + const second = resolvePluginTools(createResolveToolsParams()); + const statusTool = second.find((tool) => tool.name === "mockplugin_status"); + + expectResolvedToolNames(first, ["mockplugin_status"]); + expectResolvedToolNames(second, ["mockplugin_status"]); + expect(factory).toHaveBeenCalledTimes(1); + await expect(statusTool?.execute("call", {}, undefined)).resolves.toEqual({ + content: [{ type: "text", text: "mock-status-ok" }], + }); + expect(factory).toHaveBeenCalledTimes(2); + }); + it("reuses cached plugin tool descriptors across session identity changes", async () => { const factory = vi.fn((rawCtx: unknown) => { const ctx = rawCtx as { sessionId?: string }; diff --git a/src/plugins/tools.ts b/src/plugins/tools.ts index e0675b2bd99..957aec969e5 100644 --- a/src/plugins/tools.ts +++ b/src/plugins/tools.ts @@ -692,10 +692,10 @@ function createCachedDescriptorPluginTool(params: { for (const toolRaw of listRaw) { const malformedReason = describeMalformedPluginTool(toolRaw); if (malformedReason) { - throw new Error(`plugin tool is malformed (${pluginId}): ${malformedReason}`); + continue; } const runtimeTool = toolRaw as AnyAgentTool; - if (normalizeToolName(runtimeTool.name) === requestedToolName) { + if (normalizeToolName(readPluginToolName(runtimeTool)) === requestedToolName) { return runtimeTool; } }