mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:00:43 +00:00
test(plugins): cover config-origin tool cold load diagnostics
This commit is contained in:
@@ -277,7 +277,19 @@ function installToolManifestSnapshots(params: {
|
||||
policyHash: "test",
|
||||
generatedAtMs: 0,
|
||||
installRecords: {},
|
||||
plugins: [],
|
||||
plugins: plugins.map((plugin) => ({
|
||||
pluginId: String(plugin.id),
|
||||
origin: plugin.origin,
|
||||
enabled: true,
|
||||
enabledByDefault: plugin.enabledByDefault,
|
||||
startup: {
|
||||
sidecar: false,
|
||||
memory: false,
|
||||
deferConfiguredChannelFullLoadUntilAfterListen: false,
|
||||
agentHarnesses: [],
|
||||
},
|
||||
compat: [],
|
||||
})),
|
||||
diagnostics: [],
|
||||
},
|
||||
registryDiagnostics: [],
|
||||
@@ -301,7 +313,7 @@ function installToolManifestSnapshots(params: {
|
||||
manifestRegistryMs: 0,
|
||||
ownerMapsMs: 0,
|
||||
totalMs: 0,
|
||||
indexPluginCount: 0,
|
||||
indexPluginCount: plugins.length,
|
||||
manifestPluginCount: plugins.length,
|
||||
},
|
||||
} as never,
|
||||
@@ -491,16 +503,28 @@ describe("resolvePluginTools optional tools", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("auto-loads cold registry for path-based (bundled-origin) plugins without pre-warming (#76598)", () => {
|
||||
const config = createContext().config;
|
||||
it("auto-loads cold registry for path-based config-origin plugins without pre-warming (#76598)", () => {
|
||||
const context = {
|
||||
...createContext(),
|
||||
config: {
|
||||
...createContext().config,
|
||||
plugins: {
|
||||
...createContext().config.plugins,
|
||||
entries: {
|
||||
"optional-demo": { enabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const config = context.config;
|
||||
const registry = createToolRegistry([createOptionalDemoEntry()]);
|
||||
loadOpenClawPluginsMock.mockReturnValue(registry);
|
||||
installToolManifestSnapshot({
|
||||
config,
|
||||
plugin: {
|
||||
id: "optional-demo",
|
||||
origin: "bundled",
|
||||
enabledByDefault: true,
|
||||
origin: "config",
|
||||
enabledByDefault: undefined,
|
||||
channels: [],
|
||||
providers: [],
|
||||
contracts: {
|
||||
@@ -514,6 +538,7 @@ describe("resolvePluginTools optional tools", () => {
|
||||
// This is the regression path from PR #76004 where path-based plugin tools disappeared.
|
||||
const tools = resolvePluginTools(
|
||||
createResolveToolsParams({
|
||||
context,
|
||||
toolAllowlist: ["optional_tool"],
|
||||
}),
|
||||
);
|
||||
@@ -528,6 +553,50 @@ describe("resolvePluginTools optional tools", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("warns when cold registry load still does not provide the selected plugin tools", () => {
|
||||
const context = {
|
||||
...createContext(),
|
||||
config: {
|
||||
...createContext().config,
|
||||
plugins: {
|
||||
...createContext().config.plugins,
|
||||
entries: {
|
||||
"optional-demo": { enabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const config = context.config;
|
||||
const registry = createToolRegistry([]);
|
||||
loadOpenClawPluginsMock.mockReturnValue(registry);
|
||||
installToolManifestSnapshot({
|
||||
config,
|
||||
plugin: {
|
||||
id: "optional-demo",
|
||||
origin: "config",
|
||||
enabledByDefault: undefined,
|
||||
channels: [],
|
||||
providers: [],
|
||||
contracts: {
|
||||
tools: ["optional_tool"],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const tools = resolvePluginTools(
|
||||
createResolveToolsParams({
|
||||
context,
|
||||
toolAllowlist: ["optional_tool"],
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tools).toEqual([]);
|
||||
expectSingleDiagnosticMessage(
|
||||
registry.diagnostics,
|
||||
"plugin tool registry did not include selected plugin tools after cold load (optional-demo)",
|
||||
);
|
||||
});
|
||||
|
||||
it("does not reuse a pinned gateway registry for manifest-unavailable tools", () => {
|
||||
const config = createContext().config;
|
||||
installToolManifestSnapshot({
|
||||
|
||||
@@ -812,21 +812,47 @@ export function resolvePluginTools(params: {
|
||||
// Cold registry: path-based plugins (origin "config") registered via plugins.load.paths
|
||||
// are not pinned to any active channel/surface registry until explicitly loaded.
|
||||
// Trigger a standalone load so their tool factories become available, then retry.
|
||||
ensureStandaloneRuntimePluginRegistryLoaded({
|
||||
surface: "channel",
|
||||
requiredPluginIds: runtimePluginIds,
|
||||
loadOptions,
|
||||
});
|
||||
try {
|
||||
ensureStandaloneRuntimePluginRegistryLoaded({
|
||||
surface: "channel",
|
||||
requiredPluginIds: runtimePluginIds,
|
||||
loadOptions,
|
||||
});
|
||||
} catch (error) {
|
||||
context.logger.error(
|
||||
`failed to cold-load plugin tool registry for plugin ids [${runtimePluginIds.join(", ")}]: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}`,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
registry = resolvePluginToolRegistry({
|
||||
loadOptions,
|
||||
onlyPluginIds: runtimePluginIds,
|
||||
});
|
||||
if (!registry) {
|
||||
context.logger.warn(
|
||||
`plugin tool registry still unavailable after cold load for plugin ids [${runtimePluginIds.join(
|
||||
", ",
|
||||
)}]`,
|
||||
);
|
||||
return tools;
|
||||
}
|
||||
}
|
||||
|
||||
const scopedPluginIds = new Set(runtimePluginIds);
|
||||
const registryToolPluginIds = new Set(registry.tools.map((entry) => entry.pluginId));
|
||||
const missingRegistryToolPluginIds = runtimePluginIds.filter(
|
||||
(pluginId) => !registryToolPluginIds.has(pluginId),
|
||||
);
|
||||
for (const pluginId of missingRegistryToolPluginIds) {
|
||||
registry.diagnostics.push({
|
||||
level: "warn",
|
||||
pluginId,
|
||||
source: "plugin-tools",
|
||||
message: `plugin tool registry did not include selected plugin tools after cold load (${pluginId})`,
|
||||
});
|
||||
}
|
||||
const blockedPlugins = new Set<string>();
|
||||
const factoryTimingStartedAt = Date.now();
|
||||
const factoryTimings: PluginToolFactoryTiming[] = [];
|
||||
|
||||
Reference in New Issue
Block a user