fix(plugins): restore cached memory capability on cache hits (#65240)

Merged via squash.

Prepared head SHA: 4209f056a1
Co-authored-by: sercada <24389792+sercada@users.noreply.github.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Reviewed-by: @vincentkoc
This commit is contained in:
Sergio Cadavid
2026-04-12 05:54:55 -05:00
committed by GitHub
parent 93f2da8426
commit 8f156df4ac
3 changed files with 74 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ Docs: https://docs.openclaw.ai
- Agents/Anthropic replay: preserve immutable signed-thinking replay safety across stored and live reruns, keep non-thinking embedded `tool_result` user blocks intact, and drop conflicting preserved tool IDs before validation so retries stop degrading into omitted tool calls. (#65126) Thanks @shakkernerd.
- Telegram/direct sessions: keep commentary-only assistant fallback payloads out of visible direct delivery, so Codex planning chatter cannot leak into Telegram DMs when a run has no `final_answer` text. (#65112) Thanks @vincentkoc.
- Infra/net: fix multipart FormData fields (including `model`) being silently dropped when a guarded runtime fetch body crosses a FormData implementation boundary, restoring OpenAI audio transcription requests that failed with HTTP 400. (#64349) Thanks @petr-sloup.
- Plugins/memory: restore cached memory capability public artifacts on plugin-registry cache hits so memory-backed artifact surfaces stay visible after warm loads. Thanks @sercada and @vincentkoc.
## 2026.4.11

View File

@@ -39,7 +39,9 @@ import {
} from "./memory-embedding-providers.js";
import {
buildMemoryPromptSection,
clearMemoryPluginState,
getMemoryRuntime,
listActiveMemoryPublicArtifacts,
listMemoryCorpusSupplements,
registerMemoryCorpusSupplement,
registerMemoryFlushPlanResolver,
@@ -1809,6 +1811,73 @@ module.exports = { id: "throws-after-import", register() {} };`,
expect(listMemoryEmbeddingProviders()).toEqual([]);
});
it("restores cached memory capability public artifacts on cache hits", async () => {
useNoBundledPlugins();
const workspaceDir = makeTempDir();
const absolutePath = path.join(workspaceDir, "MEMORY.md");
fs.writeFileSync(absolutePath, "# Memory\n");
const plugin = writePlugin({
id: "cached-memory-capability",
filename: "cached-memory-capability.cjs",
body: `module.exports = {
id: "cached-memory-capability",
kind: "memory",
register(api) {
api.registerMemoryCapability({
publicArtifacts: {
async listArtifacts() {
return [{
kind: "memory-root",
workspaceDir: ${JSON.stringify(workspaceDir)},
relativePath: "MEMORY.md",
absolutePath: ${JSON.stringify(absolutePath)},
agentIds: ["main"],
contentType: "markdown",
}];
},
},
});
},
};`,
});
const options = {
workspaceDir: plugin.dir,
config: {
plugins: {
load: { paths: [plugin.file] },
allow: ["cached-memory-capability"],
slots: { memory: "cached-memory-capability" },
},
},
onlyPluginIds: ["cached-memory-capability"],
};
const expectedArtifacts = [
{
kind: "memory-root",
workspaceDir,
relativePath: "MEMORY.md",
absolutePath,
agentIds: ["main"],
contentType: "markdown" as const,
},
];
const first = loadOpenClawPlugins(options);
await expect(listActiveMemoryPublicArtifacts({ cfg: {} as never })).resolves.toEqual(
expectedArtifacts,
);
clearMemoryPluginState();
const second = loadOpenClawPlugins(options);
expect(second).toBe(first);
await expect(listActiveMemoryPublicArtifacts({ cfg: {} as never })).resolves.toEqual(
expectedArtifacts,
);
});
it("throws when activate:false is used without cache:false", () => {
expect(() => loadOpenClawPlugins({ activate: false })).toThrow(
"activate:false requires cache:false",

View File

@@ -48,6 +48,7 @@ import {
} from "./memory-embedding-providers.js";
import {
clearMemoryPluginState,
getMemoryCapabilityRegistration,
getMemoryFlushPlanResolver,
getMemoryPromptSectionBuilder,
getMemoryRuntime,
@@ -148,6 +149,7 @@ export class PluginLoadReentryError extends Error {
type CachedPluginState = {
registry: PluginRegistry;
memoryCapability: ReturnType<typeof getMemoryCapabilityRegistration>;
memoryCorpusSupplements: ReturnType<typeof listMemoryCorpusSupplements>;
agentHarnesses: ReturnType<typeof listRegisteredAgentHarnesses>;
compactionProviders: ReturnType<typeof listRegisteredCompactionProviders>;
@@ -1104,6 +1106,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
restoreRegisteredCompactionProviders(cached.compactionProviders);
restoreRegisteredMemoryEmbeddingProviders(cached.memoryEmbeddingProviders);
restoreMemoryPluginState({
capability: cached.memoryCapability,
corpusSupplements: cached.memoryCorpusSupplements,
promptBuilder: cached.memoryPromptBuilder,
promptSupplements: cached.memoryPromptSupplements,
@@ -1799,6 +1802,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
if (cacheEnabled) {
setCachedPluginRegistry(cacheKey, {
memoryCapability: getMemoryCapabilityRegistration(),
memoryCorpusSupplements: listMemoryCorpusSupplements(),
registry,
agentHarnesses: listRegisteredAgentHarnesses(),