fix(memory-core): route bundled helpers through facade

This commit is contained in:
Vincent Koc
2026-04-09 09:20:28 +01:00
parent 68781bf2c2
commit 2a372577d4
5 changed files with 141 additions and 9 deletions

View File

@@ -189,11 +189,11 @@ vi.mock("../plugins/memory-embedding-providers.js", () => ({
mocks.registerMemoryEmbeddingProvider as unknown as typeof import("../plugins/memory-embedding-providers.js").registerMemoryEmbeddingProvider,
}));
vi.mock("../../extensions/memory-core/runtime-api.js", () => ({
vi.mock("../plugin-sdk/memory-core-bundled-runtime.js", () => ({
createEmbeddingProvider:
mocks.createEmbeddingProvider as unknown as typeof import("../../extensions/memory-core/runtime-api.js").createEmbeddingProvider,
mocks.createEmbeddingProvider as unknown as typeof import("../plugin-sdk/memory-core-bundled-runtime.js").createEmbeddingProvider,
registerBuiltInMemoryEmbeddingProviders:
mocks.registerBuiltInMemoryEmbeddingProviders as typeof import("../../extensions/memory-core/runtime-api.js").registerBuiltInMemoryEmbeddingProviders,
mocks.registerBuiltInMemoryEmbeddingProviders as typeof import("../plugin-sdk/memory-core-bundled-runtime.js").registerBuiltInMemoryEmbeddingProviders,
}));
vi.mock("../image-generation/runtime.js", () => ({

View File

@@ -1,10 +1,6 @@
import fs from "node:fs/promises";
import path from "node:path";
import type { Command } from "commander";
import {
createEmbeddingProvider,
registerBuiltInMemoryEmbeddingProviders,
} from "../../extensions/memory-core/runtime-api.js";
import { agentCommand } from "../agents/agent-command.js";
import { resolveAgentDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import {
@@ -30,6 +26,10 @@ import {
import { getImageMetadata } from "../media/image-ops.js";
import { detectMime, extensionForMime, normalizeMimeType } from "../media/mime.js";
import { saveMediaBuffer } from "../media/store.js";
import {
createEmbeddingProvider,
registerBuiltInMemoryEmbeddingProviders,
} from "../plugin-sdk/memory-core-bundled-runtime.js";
import {
listMemoryEmbeddingProviders,
registerMemoryEmbeddingProvider,

View File

@@ -2,5 +2,5 @@ export {
removeBackfillDiaryEntries,
previewGroundedRemMarkdown,
writeBackfillDiaryEntries,
} from "../../../extensions/memory-core/api.js";
export { removeGroundedShortTermCandidates } from "../../../extensions/memory-core/runtime-api.js";
removeGroundedShortTermCandidates,
} from "../../plugin-sdk/memory-core-bundled-runtime.js";

View File

@@ -0,0 +1,78 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const loadBundledPluginPublicSurfaceModuleSync = vi.hoisted(() => vi.fn());
const createEmbeddingProviderImpl = vi.hoisted(() => vi.fn());
const registerBuiltInMemoryEmbeddingProvidersImpl = vi.hoisted(() => vi.fn());
const removeGroundedShortTermCandidatesImpl = vi.hoisted(() => vi.fn());
const previewGroundedRemMarkdownImpl = vi.hoisted(() => vi.fn());
const writeBackfillDiaryEntriesImpl = vi.hoisted(() => vi.fn());
const removeBackfillDiaryEntriesImpl = vi.hoisted(() => vi.fn());
vi.mock("./facade-loader.js", async () => {
const actual = await vi.importActual<typeof import("./facade-loader.js")>("./facade-loader.js");
return {
...actual,
loadBundledPluginPublicSurfaceModuleSync,
};
});
describe("plugin-sdk memory-core bundled runtime", () => {
beforeEach(() => {
createEmbeddingProviderImpl.mockReset().mockResolvedValue({ provider: { id: "openai" } });
registerBuiltInMemoryEmbeddingProvidersImpl.mockReset();
removeGroundedShortTermCandidatesImpl.mockReset().mockResolvedValue({ removed: 1 });
previewGroundedRemMarkdownImpl.mockReset().mockResolvedValue({ files: [] });
writeBackfillDiaryEntriesImpl.mockReset().mockResolvedValue({ writtenCount: 1 });
removeBackfillDiaryEntriesImpl.mockReset().mockResolvedValue({ removedCount: 1 });
loadBundledPluginPublicSurfaceModuleSync
.mockReset()
.mockImplementation(({ artifactBasename }) => {
if (artifactBasename === "runtime-api.js") {
return {
createEmbeddingProvider: createEmbeddingProviderImpl,
registerBuiltInMemoryEmbeddingProviders: registerBuiltInMemoryEmbeddingProvidersImpl,
removeGroundedShortTermCandidates: removeGroundedShortTermCandidatesImpl,
};
}
if (artifactBasename === "api.js") {
return {
previewGroundedRemMarkdown: previewGroundedRemMarkdownImpl,
writeBackfillDiaryEntries: writeBackfillDiaryEntriesImpl,
removeBackfillDiaryEntries: removeBackfillDiaryEntriesImpl,
};
}
throw new Error(`unexpected artifact ${String(artifactBasename)}`);
});
});
it("keeps the bundled memory facade cold until a helper is used", async () => {
const module = await import("./memory-core-bundled-runtime.js");
expect(loadBundledPluginPublicSurfaceModuleSync).not.toHaveBeenCalled();
await module.createEmbeddingProvider({} as never);
expect(loadBundledPluginPublicSurfaceModuleSync).toHaveBeenCalledWith({
dirName: "memory-core",
artifactBasename: "runtime-api.js",
});
});
it("delegates doctor and embedding helpers through the bundled public surfaces", async () => {
const module = await import("./memory-core-bundled-runtime.js");
await module.previewGroundedRemMarkdown({} as never);
await module.removeGroundedShortTermCandidates({} as never);
module.registerBuiltInMemoryEmbeddingProviders({} as never);
expect(previewGroundedRemMarkdownImpl).toHaveBeenCalledWith({} as never);
expect(removeGroundedShortTermCandidatesImpl).toHaveBeenCalledWith({} as never);
expect(registerBuiltInMemoryEmbeddingProvidersImpl).toHaveBeenCalledWith({} as never);
expect(loadBundledPluginPublicSurfaceModuleSync).toHaveBeenCalledWith({
dirName: "memory-core",
artifactBasename: "api.js",
});
expect(loadBundledPluginPublicSurfaceModuleSync).toHaveBeenCalledWith({
dirName: "memory-core",
artifactBasename: "runtime-api.js",
});
});
});

View File

@@ -0,0 +1,54 @@
// Manual facade. Keep loader boundary explicit.
type ApiFacadeModule = typeof import("@openclaw/memory-core/api.js");
type RuntimeFacadeModule = typeof import("@openclaw/memory-core/runtime-api.js");
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-loader.js";
function loadApiFacadeModule(): ApiFacadeModule {
return loadBundledPluginPublicSurfaceModuleSync<ApiFacadeModule>({
dirName: "memory-core",
artifactBasename: "api.js",
});
}
function loadRuntimeFacadeModule(): RuntimeFacadeModule {
return loadBundledPluginPublicSurfaceModuleSync<RuntimeFacadeModule>({
dirName: "memory-core",
artifactBasename: "runtime-api.js",
});
}
export const createEmbeddingProvider: RuntimeFacadeModule["createEmbeddingProvider"] = ((...args) =>
loadRuntimeFacadeModule().createEmbeddingProvider(
...args,
)) as RuntimeFacadeModule["createEmbeddingProvider"];
export const registerBuiltInMemoryEmbeddingProviders: RuntimeFacadeModule["registerBuiltInMemoryEmbeddingProviders"] =
((...args) =>
loadRuntimeFacadeModule().registerBuiltInMemoryEmbeddingProviders(
...args,
)) as RuntimeFacadeModule["registerBuiltInMemoryEmbeddingProviders"];
export const removeGroundedShortTermCandidates: RuntimeFacadeModule["removeGroundedShortTermCandidates"] =
((...args) =>
loadRuntimeFacadeModule().removeGroundedShortTermCandidates(
...args,
)) as RuntimeFacadeModule["removeGroundedShortTermCandidates"];
export const previewGroundedRemMarkdown: ApiFacadeModule["previewGroundedRemMarkdown"] = ((
...args
) =>
loadApiFacadeModule().previewGroundedRemMarkdown(
...args,
)) as ApiFacadeModule["previewGroundedRemMarkdown"];
export const writeBackfillDiaryEntries: ApiFacadeModule["writeBackfillDiaryEntries"] = ((...args) =>
loadApiFacadeModule().writeBackfillDiaryEntries(
...args,
)) as ApiFacadeModule["writeBackfillDiaryEntries"];
export const removeBackfillDiaryEntries: ApiFacadeModule["removeBackfillDiaryEntries"] = ((
...args
) =>
loadApiFacadeModule().removeBackfillDiaryEntries(
...args,
)) as ApiFacadeModule["removeBackfillDiaryEntries"];