mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-29 10:02:04 +00:00
feat(memory): pluggable system prompt section for memory plugins (#40126)
Merged via squash.
Prepared head SHA: 5228d1937f
Co-authored-by: jarimustonen <1272053+jarimustonen@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
This commit is contained in:
@@ -23,12 +23,13 @@ async function importFreshPluginTestModules() {
|
||||
vi.doUnmock("./hooks.js");
|
||||
vi.doUnmock("./loader.js");
|
||||
vi.doUnmock("jiti");
|
||||
const [loader, hookRunnerGlobal, hooks, runtime, registry] = await Promise.all([
|
||||
const [loader, hookRunnerGlobal, hooks, runtime, registry, promptSection] = await Promise.all([
|
||||
import("./loader.js"),
|
||||
import("./hook-runner-global.js"),
|
||||
import("./hooks.js"),
|
||||
import("./runtime.js"),
|
||||
import("./registry.js"),
|
||||
import("../memory/prompt-section.js"),
|
||||
]);
|
||||
return {
|
||||
...loader,
|
||||
@@ -36,11 +37,13 @@ async function importFreshPluginTestModules() {
|
||||
...hooks,
|
||||
...runtime,
|
||||
...registry,
|
||||
...promptSection,
|
||||
};
|
||||
}
|
||||
|
||||
const {
|
||||
__testing,
|
||||
buildMemoryPromptSection,
|
||||
clearPluginLoaderCache,
|
||||
createHookRunner,
|
||||
createEmptyPluginRegistry,
|
||||
@@ -48,6 +51,7 @@ const {
|
||||
getActivePluginRegistryKey,
|
||||
getGlobalHookRunner,
|
||||
loadOpenClawPlugins,
|
||||
registerMemoryPromptSection,
|
||||
resetGlobalHookRunner,
|
||||
setActivePluginRegistry,
|
||||
} = await importFreshPluginTestModules();
|
||||
@@ -1204,6 +1208,73 @@ module.exports = { id: "skipped-scoped-only", register() { throw new Error("skip
|
||||
clearPluginCommands();
|
||||
});
|
||||
|
||||
it("does not replace the active memory prompt section during non-activating loads", () => {
|
||||
useNoBundledPlugins();
|
||||
registerMemoryPromptSection(() => ["active memory section"]);
|
||||
const plugin = writePlugin({
|
||||
id: "snapshot-memory",
|
||||
filename: "snapshot-memory.cjs",
|
||||
body: `module.exports = {
|
||||
id: "snapshot-memory",
|
||||
kind: "memory",
|
||||
register(api) {
|
||||
api.registerMemoryPromptSection(() => ["snapshot memory section"]);
|
||||
},
|
||||
};`,
|
||||
});
|
||||
|
||||
const scoped = loadOpenClawPlugins({
|
||||
cache: false,
|
||||
activate: false,
|
||||
workspaceDir: plugin.dir,
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: ["snapshot-memory"],
|
||||
slots: { memory: "snapshot-memory" },
|
||||
},
|
||||
},
|
||||
onlyPluginIds: ["snapshot-memory"],
|
||||
});
|
||||
|
||||
expect(scoped.plugins.find((entry) => entry.id === "snapshot-memory")?.status).toBe("loaded");
|
||||
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([
|
||||
"active memory section",
|
||||
]);
|
||||
});
|
||||
|
||||
it("clears a newly-registered memory prompt section when plugin register fails", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
id: "failing-memory",
|
||||
filename: "failing-memory.cjs",
|
||||
body: `module.exports = {
|
||||
id: "failing-memory",
|
||||
kind: "memory",
|
||||
register(api) {
|
||||
api.registerMemoryPromptSection(() => ["stale failure section"]);
|
||||
throw new Error("memory register failed");
|
||||
},
|
||||
};`,
|
||||
});
|
||||
|
||||
const registry = loadOpenClawPlugins({
|
||||
cache: false,
|
||||
workspaceDir: plugin.dir,
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: ["failing-memory"],
|
||||
slots: { memory: "failing-memory" },
|
||||
},
|
||||
},
|
||||
onlyPluginIds: ["failing-memory"],
|
||||
});
|
||||
|
||||
expect(registry.plugins.find((entry) => entry.id === "failing-memory")?.status).toBe("error");
|
||||
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([]);
|
||||
});
|
||||
|
||||
it("throws when activate:false is used without cache:false", () => {
|
||||
expect(() => loadOpenClawPlugins({ activate: false })).toThrow(
|
||||
"activate:false requires cache:false",
|
||||
@@ -3787,3 +3858,16 @@ export const runtimeValue = helperValue;`,
|
||||
expect(resolved).toBe(expected === "dist" ? fixture.distFile : fixture.srcFile);
|
||||
});
|
||||
});
|
||||
|
||||
describe("clearPluginLoaderCache", () => {
|
||||
it("resets the registered memory prompt section builder", () => {
|
||||
registerMemoryPromptSection(() => ["stale memory section"]);
|
||||
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([
|
||||
"stale memory section",
|
||||
]);
|
||||
|
||||
clearPluginLoaderCache();
|
||||
|
||||
expect(buildMemoryPromptSection({ availableTools: new Set() })).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user