























@@ -9,7 +9,16 @@
99 */
10101111import { Buffer } from "node:buffer";
12-import { describe, test, expect, vi } from "vitest";
12+import fs from "node:fs/promises";
13+import path from "node:path";
14+import {
15+clearMemoryPluginState,
16+getMemoryCapabilityRegistration,
17+listActiveMemoryPublicArtifacts,
18+registerMemoryCapability,
19+type MemoryPluginCapability,
20+} from "openclaw/plugin-sdk/memory-host-core";
21+import { afterEach, describe, test, expect, vi } from "vitest";
1322import memoryPlugin, {
1423detectCategory,
1524formatRelevantMemoriesContext,
@@ -164,7 +173,11 @@ async function withMockedOpenAiMemoryPlugin<T>(params: {
164173}
165174166175describe("memory plugin e2e", () => {
167-const { getDbPath } = installTmpDirHarness({ prefix: "openclaw-memory-test-" });
176+const { getDbPath, getTmpDir } = installTmpDirHarness({ prefix: "openclaw-memory-test-" });
177+178+afterEach(() => {
179+clearMemoryPluginState();
180+});
168181169182function parseConfig(overrides: Record<string, unknown> = {}) {
170183return memoryPlugin.configSchema?.parse?.({
@@ -340,6 +353,165 @@ describe("memory plugin e2e", () => {
340353expectHookNotRegistered(on, "before_agent_start");
341354});
342355356+test("registers memory public artifact provider for memory-wiki bridge parity", async () => {
357+const workspaceDir = path.join(getTmpDir(), "workspace-public-artifacts");
358+await fs.mkdir(path.join(workspaceDir, "memory"), { recursive: true });
359+await fs.writeFile(path.join(workspaceDir, "MEMORY.md"), "# Durable Memory\n", "utf8");
360+await fs.writeFile(path.join(workspaceDir, "memory", "2026-05-18.md"), "# Daily\n", "utf8");
361+const registerMemoryCapability = vi.fn();
362+const mockApi = {
363+id: "memory-lancedb",
364+name: "Memory (LanceDB)",
365+source: "test",
366+config: {},
367+pluginConfig: {
368+embedding: {
369+apiKey: OPENAI_API_KEY,
370+model: "text-embedding-3-small",
371+},
372+dbPath: getDbPath(),
373+autoCapture: false,
374+autoRecall: false,
375+},
376+runtime: {},
377+logger: {
378+info: vi.fn(),
379+warn: vi.fn(),
380+error: vi.fn(),
381+debug: vi.fn(),
382+},
383+ registerMemoryCapability,
384+registerTool: vi.fn(),
385+registerCli: vi.fn(),
386+registerService: vi.fn(),
387+on: vi.fn(),
388+resolvePath: (filePath: string) => filePath,
389+};
390+391+memoryPlugin.register(mockApi as any);
392+const capability = firstObjectArg(
393+registerMemoryCapability as unknown as MockCallSource,
394+"memory capability",
395+);
396+const publicArtifacts = capability.publicArtifacts as
397+| { listArtifacts?: (params: { cfg: unknown }) => Promise<unknown> }
398+| undefined;
399+expect(publicArtifacts?.listArtifacts).toBeTypeOf("function");
400+401+await expect(
402+publicArtifacts?.listArtifacts?.({
403+cfg: {
404+agents: {
405+list: [{ id: "main", default: true, workspace: workspaceDir }],
406+},
407+},
408+}),
409+).resolves.toEqual([
410+{
411+kind: "memory-root",
412+ workspaceDir,
413+relativePath: "MEMORY.md",
414+absolutePath: path.join(workspaceDir, "MEMORY.md"),
415+agentIds: ["main"],
416+contentType: "markdown",
417+},
418+{
419+kind: "daily-note",
420+ workspaceDir,
421+relativePath: "memory/2026-05-18.md",
422+absolutePath: path.join(workspaceDir, "memory", "2026-05-18.md"),
423+agentIds: ["main"],
424+contentType: "markdown",
425+},
426+]);
427+});
428+429+test("preserves memory-core sidecar capability when registering public artifacts", async () => {
430+const workspaceDir = path.join(getTmpDir(), "workspace-sidecar-public-artifacts");
431+await fs.mkdir(path.join(workspaceDir, "memory"), { recursive: true });
432+await fs.writeFile(path.join(workspaceDir, "MEMORY.md"), "# Durable Memory\n", "utf8");
433+await fs.writeFile(path.join(workspaceDir, "memory", "2026-05-18.md"), "# Daily\n", "utf8");
434+const runtime = {
435+async getMemorySearchManager() {
436+return { manager: null, error: "test" };
437+},
438+resolveMemoryBackendConfig() {
439+return { backend: "builtin" as const };
440+},
441+};
442+const flushPlanResolver = vi.fn(() => ({
443+softThresholdTokens: 1,
444+forceFlushTranscriptBytes: 2,
445+reserveTokensFloor: 3,
446+prompt: "flush",
447+systemPrompt: "flush",
448+relativePath: "memory/sidecar.md",
449+}));
450+registerMemoryCapability("memory-core", {
451+ flushPlanResolver,
452+ runtime,
453+});
454+const registerMemoryCapabilityForPlugin = vi.fn((capability: MemoryPluginCapability) => {
455+registerMemoryCapability("memory-lancedb", capability);
456+});
457+const mockApi = {
458+id: "memory-lancedb",
459+name: "Memory (LanceDB)",
460+source: "test",
461+config: {},
462+pluginConfig: {
463+embedding: {
464+apiKey: OPENAI_API_KEY,
465+model: "text-embedding-3-small",
466+},
467+dbPath: getDbPath(),
468+autoCapture: false,
469+autoRecall: false,
470+},
471+runtime: {},
472+logger: {
473+info: vi.fn(),
474+warn: vi.fn(),
475+error: vi.fn(),
476+debug: vi.fn(),
477+},
478+registerMemoryCapability: registerMemoryCapabilityForPlugin,
479+registerTool: vi.fn(),
480+registerCli: vi.fn(),
481+registerService: vi.fn(),
482+on: vi.fn(),
483+resolvePath: (filePath: string) => filePath,
484+};
485+486+memoryPlugin.register(mockApi as any);
487+488+expect(registerMemoryCapabilityForPlugin).toHaveBeenCalledOnce();
489+expect(
490+getMemoryCapabilityRegistration()?.capability.flushPlanResolver?.({})?.relativePath,
491+).toBe("memory/sidecar.md");
492+expect(getMemoryCapabilityRegistration()?.capability.runtime).toBe(runtime);
493+await expect(
494+listActiveMemoryPublicArtifacts({
495+cfg: {
496+agents: {
497+list: [{ id: "main", default: true, workspace: workspaceDir }],
498+},
499+},
500+}),
501+).resolves.toMatchObject([
502+{
503+kind: "memory-root",
504+ workspaceDir,
505+relativePath: "MEMORY.md",
506+},
507+{
508+kind: "daily-note",
509+ workspaceDir,
510+relativePath: "memory/2026-05-18.md",
511+},
512+]);
513+});
514+343515test("uses provider adapter auth when embedding apiKey is omitted", async () => {
344516const embedQuery = vi.fn(async () => [0.1, 0.2, 0.3]);
345517const createProvider = vi.fn(async (options: Record<string, unknown>) => ({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。