mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:10:44 +00:00
fix: avoid stale scoped runtime registries
This commit is contained in:
@@ -161,6 +161,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
- Agents/tools: skip unavailable media generation and PDF tool factories from the live reply path when Gateway metadata and the active auth store prove no configured provider can back them, while keeping explicit config and auth-backed providers on the normal factory path. Thanks @shakkernerd.
|
||||
- Agents/runtime: reuse the Gateway metadata startup plan when ensuring reply runtime plugins are loaded, so live agent turns do not broad-load plugin runtimes after the Gateway already scoped startup activation. Thanks @shakkernerd.
|
||||
- Agents/runtime: delegate scoped reply runtime registry reuse to the plugin loader cache-key compatibility checks, so config changes with the same startup plugin ids cannot keep stale runtime hooks or tools active. Thanks @shakkernerd.
|
||||
- Agents/runtime: validate agent model allowlists against manifest model catalog metadata during reply startup, avoiding broad provider runtime catalog loading before the agent run lane starts. Thanks @shakkernerd.
|
||||
- Agents/tools: route media and generation capability lookups through the Gateway plugin metadata snapshot during reply tool registration, avoiding repeated manifest registry reloads on the live reply path. Thanks @shakkernerd.
|
||||
- Agents/tools: reuse the auth profile store already loaded for the active run when deciding media and generation tool availability, avoiding repeated provider-auth runtime discovery during reply startup. Thanks @shakkernerd.
|
||||
|
||||
@@ -3,8 +3,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
const hoisted = vi.hoisted(() => ({
|
||||
getCurrentPluginMetadataSnapshot: vi.fn(),
|
||||
resolveRuntimePluginRegistry: vi.fn(),
|
||||
getActivePluginRegistry: vi.fn(),
|
||||
getActivePluginRegistryWorkspaceDir: vi.fn(),
|
||||
getActivePluginRuntimeSubagentMode: vi.fn<() => "default" | "explicit" | "gateway-bindable">(
|
||||
() => "default",
|
||||
),
|
||||
@@ -19,8 +17,6 @@ vi.mock("../plugins/loader.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/runtime.js", () => ({
|
||||
getActivePluginRegistry: hoisted.getActivePluginRegistry,
|
||||
getActivePluginRegistryWorkspaceDir: hoisted.getActivePluginRegistryWorkspaceDir,
|
||||
getActivePluginRuntimeSubagentMode: hoisted.getActivePluginRuntimeSubagentMode,
|
||||
}));
|
||||
|
||||
@@ -32,10 +28,6 @@ describe("ensureRuntimePluginsLoaded", () => {
|
||||
hoisted.getCurrentPluginMetadataSnapshot.mockReturnValue(undefined);
|
||||
hoisted.resolveRuntimePluginRegistry.mockReset();
|
||||
hoisted.resolveRuntimePluginRegistry.mockReturnValue(undefined);
|
||||
hoisted.getActivePluginRegistry.mockReset();
|
||||
hoisted.getActivePluginRegistry.mockReturnValue(null);
|
||||
hoisted.getActivePluginRegistryWorkspaceDir.mockReset();
|
||||
hoisted.getActivePluginRegistryWorkspaceDir.mockReturnValue(undefined);
|
||||
hoisted.getActivePluginRuntimeSubagentMode.mockReset();
|
||||
hoisted.getActivePluginRuntimeSubagentMode.mockReturnValue("default");
|
||||
vi.resetModules();
|
||||
@@ -98,17 +90,13 @@ describe("ensureRuntimePluginsLoaded", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("reuses an active gateway registry that already covers the startup plan", async () => {
|
||||
it("delegates startup-scope registry reuse to loader cache compatibility", async () => {
|
||||
hoisted.getCurrentPluginMetadataSnapshot.mockReturnValue({
|
||||
startup: {
|
||||
pluginIds: ["telegram"],
|
||||
},
|
||||
});
|
||||
hoisted.getActivePluginRuntimeSubagentMode.mockReturnValue("gateway-bindable");
|
||||
hoisted.getActivePluginRegistryWorkspaceDir.mockReturnValue("/tmp/workspace");
|
||||
hoisted.getActivePluginRegistry.mockReturnValue({
|
||||
plugins: [{ id: "telegram", status: "loaded" }],
|
||||
});
|
||||
|
||||
ensureRuntimePluginsLoaded({
|
||||
config: {} as never,
|
||||
@@ -116,28 +104,49 @@ describe("ensureRuntimePluginsLoaded", () => {
|
||||
allowGatewaySubagentBinding: true,
|
||||
});
|
||||
|
||||
expect(hoisted.resolveRuntimePluginRegistry).not.toHaveBeenCalled();
|
||||
expect(hoisted.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
config: {} as never,
|
||||
installBundledRuntimeDeps: false,
|
||||
onlyPluginIds: ["telegram"],
|
||||
workspaceDir: "/tmp/workspace",
|
||||
runtimeOptions: {
|
||||
allowGatewaySubagentBinding: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("does not reuse an active gateway registry for another workspace", async () => {
|
||||
it("lets the loader decide when startup ids match but config changes", async () => {
|
||||
const config = {
|
||||
plugins: {
|
||||
config: {
|
||||
telegram: {
|
||||
replyMode: "changed",
|
||||
},
|
||||
},
|
||||
},
|
||||
} as never;
|
||||
hoisted.getCurrentPluginMetadataSnapshot.mockReturnValue({
|
||||
startup: {
|
||||
pluginIds: ["telegram"],
|
||||
},
|
||||
});
|
||||
hoisted.getActivePluginRuntimeSubagentMode.mockReturnValue("gateway-bindable");
|
||||
hoisted.getActivePluginRegistryWorkspaceDir.mockReturnValue("/tmp/other-workspace");
|
||||
hoisted.getActivePluginRegistry.mockReturnValue({
|
||||
plugins: [{ id: "telegram", status: "loaded" }],
|
||||
});
|
||||
|
||||
ensureRuntimePluginsLoaded({
|
||||
config: {} as never,
|
||||
config,
|
||||
workspaceDir: "/tmp/workspace",
|
||||
allowGatewaySubagentBinding: true,
|
||||
});
|
||||
|
||||
expect(hoisted.resolveRuntimePluginRegistry).toHaveBeenCalledTimes(1);
|
||||
expect(hoisted.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
config,
|
||||
installBundledRuntimeDeps: false,
|
||||
onlyPluginIds: ["telegram"],
|
||||
workspaceDir: "/tmp/workspace",
|
||||
runtimeOptions: {
|
||||
allowGatewaySubagentBinding: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("does not enable gateway subagent binding for normal runtime loads", async () => {
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { getCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-metadata-snapshot.js";
|
||||
import { resolveRuntimePluginRegistry } from "../plugins/loader.js";
|
||||
import {
|
||||
getActivePluginRegistry,
|
||||
getActivePluginRegistryWorkspaceDir,
|
||||
getActivePluginRuntimeSubagentMode,
|
||||
} from "../plugins/runtime.js";
|
||||
import { getActivePluginRuntimeSubagentMode } from "../plugins/runtime.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
|
||||
type StartupScopedPluginSnapshot = NonNullable<
|
||||
@@ -31,33 +27,6 @@ function resolveStartupPluginIdsFromCurrentSnapshot(params: {
|
||||
return pluginIds.filter((pluginId): pluginId is string => typeof pluginId === "string");
|
||||
}
|
||||
|
||||
function activeRegistryCoversStartupScope(params: {
|
||||
pluginIds: readonly string[];
|
||||
workspaceDir?: string;
|
||||
allowGatewaySubagentBinding: boolean;
|
||||
}): boolean {
|
||||
const activeRegistry = getActivePluginRegistry();
|
||||
if (!activeRegistry) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
params.allowGatewaySubagentBinding &&
|
||||
getActivePluginRuntimeSubagentMode() !== "gateway-bindable"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const activeWorkspaceDir = getActivePluginRegistryWorkspaceDir();
|
||||
if (
|
||||
activeWorkspaceDir !== undefined &&
|
||||
params.workspaceDir !== undefined &&
|
||||
activeWorkspaceDir !== params.workspaceDir
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const activePluginIds = new Set(activeRegistry.plugins.map((plugin) => plugin.id));
|
||||
return params.pluginIds.every((pluginId) => activePluginIds.has(pluginId));
|
||||
}
|
||||
|
||||
export function ensureRuntimePluginsLoaded(params: {
|
||||
config?: OpenClawConfig;
|
||||
workspaceDir?: string | null;
|
||||
@@ -74,16 +43,6 @@ export function ensureRuntimePluginsLoaded(params: {
|
||||
config: params.config,
|
||||
workspaceDir,
|
||||
});
|
||||
if (
|
||||
startupPluginIds &&
|
||||
activeRegistryCoversStartupScope({
|
||||
pluginIds: startupPluginIds,
|
||||
workspaceDir,
|
||||
allowGatewaySubagentBinding,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const loadOptions = {
|
||||
config: params.config,
|
||||
workspaceDir,
|
||||
|
||||
Reference in New Issue
Block a user