mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-11 11:53:32 +02:00
fix: preserve gateway-bindable loader compatibility
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
} from "./memory-state.js";
|
||||
import { createEmptyPluginRegistry } from "./registry.js";
|
||||
import { setActivePluginRegistry } from "./runtime.js";
|
||||
import type { CreatePluginRuntimeOptions } from "./runtime/index.js";
|
||||
|
||||
afterEach(() => {
|
||||
resetPluginLoaderTestStateForTest();
|
||||
@@ -39,7 +40,7 @@ describe("getCompatibleActivePluginRegistry", () => {
|
||||
},
|
||||
};
|
||||
const { cacheKey } = __testing.resolvePluginLoadCacheContext(loadOptions);
|
||||
setActivePluginRegistry(registry, cacheKey);
|
||||
setActivePluginRegistry(registry, cacheKey, "gateway-bindable");
|
||||
|
||||
expect(__testing.getCompatibleActivePluginRegistry(loadOptions)).toBe(registry);
|
||||
expect(
|
||||
@@ -59,6 +60,38 @@ describe("getCompatibleActivePluginRegistry", () => {
|
||||
...loadOptions,
|
||||
runtimeOptions: undefined,
|
||||
}),
|
||||
).toBe(registry);
|
||||
expect(
|
||||
__testing.getCompatibleActivePluginRegistry({
|
||||
...loadOptions,
|
||||
runtimeOptions: {
|
||||
subagent: {} as CreatePluginRuntimeOptions["subagent"],
|
||||
},
|
||||
}),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not treat a default-mode active registry as compatible with gateway binding", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
const loadOptions = {
|
||||
config: {
|
||||
plugins: {
|
||||
allow: ["demo"],
|
||||
load: { paths: ["/tmp/demo.js"] },
|
||||
},
|
||||
},
|
||||
workspaceDir: "/tmp/workspace-a",
|
||||
};
|
||||
const { cacheKey } = __testing.resolvePluginLoadCacheContext(loadOptions);
|
||||
setActivePluginRegistry(registry, cacheKey, "default");
|
||||
|
||||
expect(
|
||||
__testing.getCompatibleActivePluginRegistry({
|
||||
...loadOptions,
|
||||
runtimeOptions: {
|
||||
allowGatewaySubagentBinding: true,
|
||||
},
|
||||
}),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
listImportedRuntimePluginIds,
|
||||
setActivePluginRegistry,
|
||||
} from "./runtime.js";
|
||||
import type { PluginSdkResolutionPreference } from "./sdk-alias.js";
|
||||
let cachedBundledTelegramDir = "";
|
||||
let cachedBundledMemoryDir = "";
|
||||
const BUNDLED_TELEGRAM_PLUGIN_BODY = `module.exports = {
|
||||
@@ -1779,7 +1780,41 @@ module.exports = { id: "throws-after-import", register() {} };`,
|
||||
loadVariant: () =>
|
||||
loadOpenClawPlugins({
|
||||
...options,
|
||||
pluginSdkResolution: "workspace" as const,
|
||||
pluginSdkResolution: "workspace" as PluginSdkResolutionPreference,
|
||||
}),
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "does not reuse cached registries across gateway subagent binding modes",
|
||||
setup: () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
id: "cache-gateway-shared",
|
||||
filename: "cache-gateway-shared.cjs",
|
||||
body: `module.exports = { id: "cache-gateway-shared", register() {} };`,
|
||||
});
|
||||
|
||||
const options = {
|
||||
workspaceDir: plugin.dir,
|
||||
config: {
|
||||
plugins: {
|
||||
allow: ["cache-gateway-shared"],
|
||||
load: {
|
||||
paths: [plugin.file],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
loadFirst: () => loadOpenClawPlugins(options),
|
||||
loadVariant: () =>
|
||||
loadOpenClawPlugins({
|
||||
...options,
|
||||
runtimeOptions: {
|
||||
allowGatewaySubagentBinding: true,
|
||||
},
|
||||
}),
|
||||
};
|
||||
},
|
||||
@@ -1788,34 +1823,6 @@ module.exports = { id: "throws-after-import", register() {} };`,
|
||||
expectCacheMissThenHit(setup());
|
||||
});
|
||||
|
||||
it("reuses cached registry across gateway subagent binding modes", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
id: "cache-gateway-shared",
|
||||
filename: "cache-gateway-shared.cjs",
|
||||
body: `module.exports = { id: "cache-gateway-shared", register() {} };`,
|
||||
});
|
||||
|
||||
const options = {
|
||||
workspaceDir: plugin.dir,
|
||||
config: {
|
||||
plugins: {
|
||||
allow: ["cache-gateway-shared"],
|
||||
load: {
|
||||
paths: [plugin.file],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const first = loadOpenClawPlugins(options);
|
||||
const second = loadOpenClawPlugins({
|
||||
...options,
|
||||
runtimeOptions: { allowGatewaySubagentBinding: true },
|
||||
});
|
||||
expect(second).toBe(first);
|
||||
});
|
||||
|
||||
it("evicts least recently used registries when the loader cache exceeds its cap", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
|
||||
@@ -49,6 +49,7 @@ import { resolvePluginCacheInputs } from "./roots.js";
|
||||
import {
|
||||
getActivePluginRegistry,
|
||||
getActivePluginRegistryKey,
|
||||
getActivePluginRuntimeSubagentMode,
|
||||
recordImportedPluginId,
|
||||
setActivePluginRegistry,
|
||||
} from "./runtime.js";
|
||||
@@ -285,6 +286,7 @@ function buildCacheKey(params: {
|
||||
includeSetupOnlyChannelPlugins?: boolean;
|
||||
preferSetupRuntimeForChannelPlugins?: boolean;
|
||||
loadModules?: boolean;
|
||||
runtimeSubagentMode?: "default" | "explicit" | "gateway-bindable";
|
||||
pluginSdkResolution?: PluginSdkResolutionPreference;
|
||||
coreGatewayMethodNames?: string[];
|
||||
}): string {
|
||||
@@ -314,13 +316,14 @@ function buildCacheKey(params: {
|
||||
const startupChannelMode =
|
||||
params.preferSetupRuntimeForChannelPlugins === true ? "prefer-setup" : "full";
|
||||
const moduleLoadMode = params.loadModules === false ? "manifest-only" : "load-modules";
|
||||
const runtimeSubagentMode = params.runtimeSubagentMode ?? "default";
|
||||
const gatewayMethodsKey = JSON.stringify(params.coreGatewayMethodNames ?? []);
|
||||
return `${roots.workspace ?? ""}::${roots.global ?? ""}::${roots.stock ?? ""}::${JSON.stringify({
|
||||
...params.plugins,
|
||||
installs,
|
||||
loadPaths,
|
||||
activationMetadataKey: params.activationMetadataKey ?? "",
|
||||
})}::${scopeKey}::${setupOnlyKey}::${startupChannelMode}::${moduleLoadMode}::${params.pluginSdkResolution ?? "auto"}::${gatewayMethodsKey}`;
|
||||
})}::${scopeKey}::${setupOnlyKey}::${startupChannelMode}::${moduleLoadMode}::${runtimeSubagentMode}::${params.pluginSdkResolution ?? "auto"}::${gatewayMethodsKey}`;
|
||||
}
|
||||
|
||||
function normalizeScopedPluginIds(ids?: string[]): string[] | undefined {
|
||||
@@ -419,6 +422,7 @@ function resolvePluginLoadCacheContext(options: PluginLoadOptions = {}) {
|
||||
const onlyPluginIds = normalizeScopedPluginIds(options.onlyPluginIds);
|
||||
const includeSetupOnlyChannelPlugins = options.includeSetupOnlyChannelPlugins === true;
|
||||
const preferSetupRuntimeForChannelPlugins = options.preferSetupRuntimeForChannelPlugins === true;
|
||||
const runtimeSubagentMode = resolveRuntimeSubagentMode(options.runtimeOptions);
|
||||
const coreGatewayMethodNames = Object.keys(options.coreGatewayHandlers ?? {}).toSorted();
|
||||
const cacheKey = buildCacheKey({
|
||||
workspaceDir: options.workspaceDir,
|
||||
@@ -433,6 +437,7 @@ function resolvePluginLoadCacheContext(options: PluginLoadOptions = {}) {
|
||||
includeSetupOnlyChannelPlugins,
|
||||
preferSetupRuntimeForChannelPlugins,
|
||||
loadModules: options.loadModules,
|
||||
runtimeSubagentMode,
|
||||
pluginSdkResolution: options.pluginSdkResolution,
|
||||
coreGatewayMethodNames,
|
||||
});
|
||||
@@ -448,7 +453,7 @@ function resolvePluginLoadCacheContext(options: PluginLoadOptions = {}) {
|
||||
preferSetupRuntimeForChannelPlugins,
|
||||
shouldActivate: options.activate !== false,
|
||||
shouldLoadModules: options.loadModules !== false,
|
||||
runtimeSubagentMode: resolveRuntimeSubagentMode(options.runtimeOptions),
|
||||
runtimeSubagentMode,
|
||||
cacheKey,
|
||||
};
|
||||
}
|
||||
@@ -467,9 +472,26 @@ function getCompatibleActivePluginRegistry(
|
||||
if (!activeCacheKey) {
|
||||
return undefined;
|
||||
}
|
||||
return resolvePluginLoadCacheContext(options).cacheKey === activeCacheKey
|
||||
? activeRegistry
|
||||
: undefined;
|
||||
const loadContext = resolvePluginLoadCacheContext(options);
|
||||
if (loadContext.cacheKey === activeCacheKey) {
|
||||
return activeRegistry;
|
||||
}
|
||||
if (
|
||||
loadContext.runtimeSubagentMode === "default" &&
|
||||
getActivePluginRuntimeSubagentMode() === "gateway-bindable"
|
||||
) {
|
||||
const gatewayBindableCacheKey = resolvePluginLoadCacheContext({
|
||||
...options,
|
||||
runtimeOptions: {
|
||||
...options.runtimeOptions,
|
||||
allowGatewaySubagentBinding: true,
|
||||
},
|
||||
}).cacheKey;
|
||||
if (gatewayBindableCacheKey === activeCacheKey) {
|
||||
return activeRegistry;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function resolveRuntimePluginRegistry(
|
||||
|
||||
Reference in New Issue
Block a user