mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-06 14:51:08 +00:00
190 lines
5.8 KiB
TypeScript
190 lines
5.8 KiB
TypeScript
import { afterEach, describe, expect, it } from "vitest";
|
|
import { __testing, clearPluginLoaderCache, resolveRuntimePluginRegistry } from "./loader.js";
|
|
import { resetPluginLoaderTestStateForTest } from "./loader.test-fixtures.js";
|
|
import {
|
|
getMemoryEmbeddingProvider,
|
|
registerMemoryEmbeddingProvider,
|
|
} from "./memory-embedding-providers.js";
|
|
import {
|
|
buildMemoryPromptSection,
|
|
getMemoryRuntime,
|
|
registerMemoryFlushPlanResolver,
|
|
registerMemoryPromptSection,
|
|
registerMemoryRuntime,
|
|
resolveMemoryFlushPlan,
|
|
} from "./memory-state.js";
|
|
import { createEmptyPluginRegistry } from "./registry.js";
|
|
import { setActivePluginRegistry } from "./runtime.js";
|
|
|
|
afterEach(() => {
|
|
resetPluginLoaderTestStateForTest();
|
|
});
|
|
|
|
describe("getCompatibleActivePluginRegistry", () => {
|
|
it("reuses the active registry only when the load context cache key matches", () => {
|
|
const registry = createEmptyPluginRegistry();
|
|
const loadOptions = {
|
|
config: {
|
|
plugins: {
|
|
allow: ["demo"],
|
|
load: { paths: ["/tmp/demo.js"] },
|
|
},
|
|
},
|
|
workspaceDir: "/tmp/workspace-a",
|
|
runtimeOptions: {
|
|
allowGatewaySubagentBinding: true,
|
|
},
|
|
};
|
|
const { cacheKey } = __testing.resolvePluginLoadCacheContext(loadOptions);
|
|
setActivePluginRegistry(registry, cacheKey);
|
|
|
|
expect(__testing.getCompatibleActivePluginRegistry(loadOptions)).toBe(registry);
|
|
expect(
|
|
__testing.getCompatibleActivePluginRegistry({
|
|
...loadOptions,
|
|
workspaceDir: "/tmp/workspace-b",
|
|
}),
|
|
).toBeUndefined();
|
|
expect(
|
|
__testing.getCompatibleActivePluginRegistry({
|
|
...loadOptions,
|
|
onlyPluginIds: ["demo"],
|
|
}),
|
|
).toBeUndefined();
|
|
expect(
|
|
__testing.getCompatibleActivePluginRegistry({
|
|
...loadOptions,
|
|
runtimeOptions: undefined,
|
|
}),
|
|
).toBeUndefined();
|
|
});
|
|
|
|
it("does not embed activation secrets in the loader cache key", () => {
|
|
const { cacheKey } = __testing.resolvePluginLoadCacheContext({
|
|
config: {
|
|
plugins: {
|
|
allow: ["telegram"],
|
|
},
|
|
},
|
|
activationSourceConfig: {
|
|
plugins: {
|
|
allow: ["telegram"],
|
|
},
|
|
channels: {
|
|
telegram: {
|
|
enabled: true,
|
|
botToken: "secret-token",
|
|
},
|
|
},
|
|
},
|
|
autoEnabledReasons: {
|
|
telegram: ["telegram configured"],
|
|
},
|
|
});
|
|
|
|
expect(cacheKey).not.toContain("secret-token");
|
|
expect(cacheKey).not.toContain("botToken");
|
|
expect(cacheKey).not.toContain("telegram configured");
|
|
});
|
|
|
|
it("falls back to the current active runtime when no compatibility-shaping inputs are supplied", () => {
|
|
const registry = createEmptyPluginRegistry();
|
|
setActivePluginRegistry(registry, "startup-registry");
|
|
|
|
expect(__testing.getCompatibleActivePluginRegistry()).toBe(registry);
|
|
});
|
|
|
|
it("does not reuse the active registry when core gateway method names differ", () => {
|
|
const registry = createEmptyPluginRegistry();
|
|
const loadOptions = {
|
|
config: {
|
|
plugins: {
|
|
allow: ["demo"],
|
|
load: { paths: ["/tmp/demo.js"] },
|
|
},
|
|
},
|
|
workspaceDir: "/tmp/workspace-a",
|
|
coreGatewayHandlers: {
|
|
"sessions.get": () => undefined,
|
|
},
|
|
};
|
|
const { cacheKey } = __testing.resolvePluginLoadCacheContext(loadOptions);
|
|
setActivePluginRegistry(registry, cacheKey);
|
|
|
|
expect(__testing.getCompatibleActivePluginRegistry(loadOptions)).toBe(registry);
|
|
expect(
|
|
__testing.getCompatibleActivePluginRegistry({
|
|
...loadOptions,
|
|
coreGatewayHandlers: {
|
|
"sessions.get": () => undefined,
|
|
"sessions.list": () => undefined,
|
|
},
|
|
}),
|
|
).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("resolveRuntimePluginRegistry", () => {
|
|
it("reuses the compatible active registry before attempting a fresh load", () => {
|
|
const registry = createEmptyPluginRegistry();
|
|
const loadOptions = {
|
|
config: {
|
|
plugins: {
|
|
allow: ["demo"],
|
|
},
|
|
},
|
|
workspaceDir: "/tmp/workspace-a",
|
|
};
|
|
const { cacheKey } = __testing.resolvePluginLoadCacheContext(loadOptions);
|
|
setActivePluginRegistry(registry, cacheKey);
|
|
|
|
expect(resolveRuntimePluginRegistry(loadOptions)).toBe(registry);
|
|
});
|
|
|
|
it("falls back to the current active runtime when no explicit load context is provided", () => {
|
|
const registry = createEmptyPluginRegistry();
|
|
setActivePluginRegistry(registry, "startup-registry");
|
|
|
|
expect(resolveRuntimePluginRegistry()).toBe(registry);
|
|
});
|
|
});
|
|
|
|
describe("clearPluginLoaderCache", () => {
|
|
it("resets registered memory plugin registries", () => {
|
|
registerMemoryEmbeddingProvider({
|
|
id: "stale",
|
|
create: async () => ({ provider: null }),
|
|
});
|
|
registerMemoryPromptSection(() => ["stale memory section"]);
|
|
registerMemoryFlushPlanResolver(() => ({
|
|
softThresholdTokens: 1,
|
|
forceFlushTranscriptBytes: 2,
|
|
reserveTokensFloor: 3,
|
|
prompt: "stale",
|
|
systemPrompt: "stale",
|
|
relativePath: "memory/stale.md",
|
|
}));
|
|
registerMemoryRuntime({
|
|
async getMemorySearchManager() {
|
|
return { manager: null };
|
|
},
|
|
resolveMemoryBackendConfig() {
|
|
return { backend: "builtin" as const };
|
|
},
|
|
});
|
|
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([
|
|
"stale memory section",
|
|
]);
|
|
expect(resolveMemoryFlushPlan({})?.relativePath).toBe("memory/stale.md");
|
|
expect(getMemoryRuntime()).toBeDefined();
|
|
expect(getMemoryEmbeddingProvider("stale")).toBeDefined();
|
|
|
|
clearPluginLoaderCache();
|
|
|
|
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([]);
|
|
expect(resolveMemoryFlushPlan({})).toBeNull();
|
|
expect(getMemoryRuntime()).toBeUndefined();
|
|
expect(getMemoryEmbeddingProvider("stale")).toBeUndefined();
|
|
});
|
|
});
|