mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 17:00:50 +00:00
fix(plugins): restore cold-registry load for path-based plugin tools (#76598)
`resolvePluginTools` returned an empty tool list when no pre-warmed channel/active registry was found after startup — the on-demand fallback removed by PR #76004 was only added back for memory and capability-provider surfaces, leaving path-based (origin "config") plugin tool factories silent. Fix: when `resolvePluginToolRegistry` returns null, trigger a standalone registry load via `ensureStandaloneRuntimePluginRegistryLoaded`, then retry. Adds regression test asserting tools are resolved without pre-warming. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ Docs: https://docs.openclaw.ai
|
||||
- CLI/config: keep JSON dry-run patches validating touched channel configuration against bundled channel schemas even when the patch only contains SecretRef objects.
|
||||
- Plugins/tools: keep disabled bundled tool plugins out of explicit runtime allowlist ownership and fall back from loaded-but-empty channel registries to tool-bearing plugin registries, so Active Memory can use bundled `memory-core` search/get tools even when `memory-lancedb` is disabled. Fixes #76603. Thanks @jwong-art.
|
||||
- Plugins/install: run `npm install` from the managed npm-root manifest so installing one `@openclaw/*` plugin preserves already installed sibling plugins instead of pruning them. Fixes #76571. (#76602) Thanks @byungskers and @crpol.
|
||||
- Plugins/tools: restore on-demand registry load for path-based plugins (origin "config") so tool factories registered via `plugins.load.paths` are resolved at agent request time when no pre-warmed channel registry is present; prevents "unknown method" errors after gateway startup. Fixes #76598. Thanks @hclsys.
|
||||
- Channels/QQ Bot: resolve structured `clientSecret` SecretRefs before QQ token exchange, expose the QQ Bot secret contract to secrets tooling, and reject legacy `secretref:/...` marker strings. (#74772) Thanks @xialonglee.
|
||||
- Agents: keep active streamed provider replies alive by refreshing guarded fetch timeouts on raw body chunks and surface true prompt stream timeouts as explicit errors instead of partial assistant fragments. Fixes #76307. (#76633) Thanks @MkDev11.
|
||||
- Plugins/externalization: keep official ACPX, Google Chat, and LINE install specs on production package names, leaving beta-tag probing to the explicit OpenClaw beta update channel. Thanks @vincentkoc.
|
||||
|
||||
@@ -491,6 +491,43 @@ describe("resolvePluginTools optional tools", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("auto-loads cold registry for path-based (bundled-origin) plugins without pre-warming (#76598)", () => {
|
||||
const config = createContext().config;
|
||||
const registry = createToolRegistry([createOptionalDemoEntry()]);
|
||||
loadOpenClawPluginsMock.mockReturnValue(registry);
|
||||
installToolManifestSnapshot({
|
||||
config,
|
||||
plugin: {
|
||||
id: "optional-demo",
|
||||
origin: "bundled",
|
||||
enabledByDefault: true,
|
||||
channels: [],
|
||||
providers: [],
|
||||
contracts: {
|
||||
tools: ["optional_tool"],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// No ensureStandalonePluginToolRegistryLoaded pre-call and no pinned channel registry —
|
||||
// resolvePluginTools must trigger standalone load itself when the registry is cold.
|
||||
// This is the regression path from PR #76004 where path-based plugin tools disappeared.
|
||||
const tools = resolvePluginTools(
|
||||
createResolveToolsParams({
|
||||
toolAllowlist: ["optional_tool"],
|
||||
}),
|
||||
);
|
||||
|
||||
expectResolvedToolNames(tools, ["optional_tool"]);
|
||||
expect(loadOpenClawPluginsMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
activate: false,
|
||||
onlyPluginIds: ["optional-demo"],
|
||||
toolDiscovery: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not reuse a pinned gateway registry for manifest-unavailable tools", () => {
|
||||
const config = createContext().config;
|
||||
installToolManifestSnapshot({
|
||||
|
||||
@@ -804,12 +804,26 @@ export function resolvePluginTools(params: {
|
||||
onlyPluginIds: runtimePluginIds,
|
||||
runtimeOptions,
|
||||
});
|
||||
const registry = resolvePluginToolRegistry({
|
||||
let registry = resolvePluginToolRegistry({
|
||||
loadOptions,
|
||||
onlyPluginIds: runtimePluginIds,
|
||||
});
|
||||
if (!registry) {
|
||||
return tools;
|
||||
// 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,
|
||||
});
|
||||
registry = resolvePluginToolRegistry({
|
||||
loadOptions,
|
||||
onlyPluginIds: runtimePluginIds,
|
||||
});
|
||||
if (!registry) {
|
||||
return tools;
|
||||
}
|
||||
}
|
||||
|
||||
const scopedPluginIds = new Set(runtimePluginIds);
|
||||
|
||||
Reference in New Issue
Block a user