mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-15 23:50:44 +00:00
fix(plugins): respect manifest optional tool siblings
This commit is contained in:
@@ -1214,6 +1214,62 @@ describe("resolvePluginTools optional tools", () => {
|
||||
expect(loadOpenClawPluginsMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not materialize manifest-optional sibling tools from non-optional factories by default", async () => {
|
||||
const config = createContext().config;
|
||||
installToolManifestSnapshot({
|
||||
config,
|
||||
plugin: {
|
||||
id: "multi",
|
||||
origin: "bundled",
|
||||
enabledByDefault: true,
|
||||
channels: [],
|
||||
providers: [],
|
||||
contracts: {
|
||||
tools: ["other_tool", "optional_tool"],
|
||||
},
|
||||
toolMetadata: {
|
||||
optional_tool: {
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const factory = vi.fn(() => [makeTool("other_tool"), makeTool("optional_tool")]);
|
||||
setActivePluginRegistry(
|
||||
createToolRegistry([
|
||||
{
|
||||
pluginId: "multi",
|
||||
optional: false,
|
||||
source: "/tmp/multi.js",
|
||||
names: ["other_tool", "optional_tool"],
|
||||
declaredNames: ["other_tool", "optional_tool"],
|
||||
factory,
|
||||
},
|
||||
]) as never,
|
||||
"test-tool-registry",
|
||||
"gateway-bindable",
|
||||
"/tmp",
|
||||
);
|
||||
const { loadManifestContractSnapshot } = await import("./manifest-contract-eligibility.js");
|
||||
const snapshot = loadManifestContractSnapshot({ config, workspaceDir: "/tmp" });
|
||||
expect(
|
||||
snapshot.plugins.find((plugin) => plugin.id === "multi")?.toolMetadata?.optional_tool,
|
||||
).toMatchObject({ optional: true });
|
||||
|
||||
const tools = resolvePluginTools(
|
||||
createResolveToolsParams({
|
||||
context: {
|
||||
...createContext(),
|
||||
config,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expectResolvedToolNames(tools, ["other_tool"]);
|
||||
expect(factory).toHaveBeenCalledTimes(1);
|
||||
expect(loadOpenClawPluginsMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects plugin id collisions with core tool names", () => {
|
||||
const registry = setRegistry([
|
||||
{
|
||||
|
||||
@@ -1053,16 +1053,43 @@ export function resolvePluginTools(params: {
|
||||
continue;
|
||||
}
|
||||
const listRaw: unknown[] = Array.isArray(resolved) ? resolved : [resolved];
|
||||
const selectedManifestToolNames =
|
||||
manifestPlugin && availabilityNames.length > 0
|
||||
? new Set(allowlistNames.map((name) => normalizeToolName(name)))
|
||||
: undefined;
|
||||
const manifestContractToolNames =
|
||||
manifestPlugin && availabilityNames.length > 0
|
||||
? new Set(availabilityNames.map((name) => normalizeToolName(name)))
|
||||
: undefined;
|
||||
const availableList = manifestPlugin
|
||||
? listRaw.filter((tool) =>
|
||||
isManifestToolNameAvailable({
|
||||
? listRaw.filter((tool) => {
|
||||
const toolName = readPluginToolName(tool);
|
||||
const normalizedToolName = normalizeToolName(toolName);
|
||||
if (
|
||||
isManifestToolOptional(manifestPlugin, toolName) &&
|
||||
!isOptionalToolAllowed({
|
||||
toolName,
|
||||
pluginId: entry.pluginId,
|
||||
allowlist,
|
||||
})
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
selectedManifestToolNames &&
|
||||
manifestContractToolNames?.has(normalizedToolName) &&
|
||||
!selectedManifestToolNames.has(normalizedToolName)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return isManifestToolNameAvailable({
|
||||
plugin: manifestPlugin,
|
||||
toolName: readPluginToolName(tool),
|
||||
toolName,
|
||||
config: params.context.runtimeConfig ?? context.config,
|
||||
env,
|
||||
hasAuthForProvider: params.hasAuthForProvider,
|
||||
}),
|
||||
)
|
||||
});
|
||||
})
|
||||
: listRaw;
|
||||
const policyAvailableList = availableList.filter(
|
||||
(tool) =>
|
||||
|
||||
Reference in New Issue
Block a user