mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-23 07:01:40 +00:00
feat(memory-sdk): add memory event journal bridge
This commit is contained in:
93
src/memory-host-sdk/events.ts
Normal file
93
src/memory-host-sdk/events.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { MemoryDreamingPhaseName } from "./dreaming.js";
|
||||
|
||||
export const MEMORY_HOST_EVENT_LOG_RELATIVE_PATH = path.join("memory", ".dreams", "events.jsonl");
|
||||
|
||||
export type MemoryHostRecallRecordedEvent = {
|
||||
type: "memory.recall.recorded";
|
||||
timestamp: string;
|
||||
query: string;
|
||||
resultCount: number;
|
||||
results: Array<{
|
||||
path: string;
|
||||
startLine: number;
|
||||
endLine: number;
|
||||
score: number;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type MemoryHostPromotionAppliedEvent = {
|
||||
type: "memory.promotion.applied";
|
||||
timestamp: string;
|
||||
memoryPath: string;
|
||||
applied: number;
|
||||
candidates: Array<{
|
||||
key: string;
|
||||
path: string;
|
||||
startLine: number;
|
||||
endLine: number;
|
||||
score: number;
|
||||
recallCount: number;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type MemoryHostDreamCompletedEvent = {
|
||||
type: "memory.dream.completed";
|
||||
timestamp: string;
|
||||
phase: MemoryDreamingPhaseName;
|
||||
inlinePath?: string;
|
||||
reportPath?: string;
|
||||
lineCount: number;
|
||||
storageMode: "inline" | "separate" | "both";
|
||||
};
|
||||
|
||||
export type MemoryHostEvent =
|
||||
| MemoryHostRecallRecordedEvent
|
||||
| MemoryHostPromotionAppliedEvent
|
||||
| MemoryHostDreamCompletedEvent;
|
||||
|
||||
export function resolveMemoryHostEventLogPath(workspaceDir: string): string {
|
||||
return path.join(workspaceDir, MEMORY_HOST_EVENT_LOG_RELATIVE_PATH);
|
||||
}
|
||||
|
||||
export async function appendMemoryHostEvent(
|
||||
workspaceDir: string,
|
||||
event: MemoryHostEvent,
|
||||
): Promise<void> {
|
||||
const eventLogPath = resolveMemoryHostEventLogPath(workspaceDir);
|
||||
await fs.mkdir(path.dirname(eventLogPath), { recursive: true });
|
||||
await fs.appendFile(eventLogPath, `${JSON.stringify(event)}\n`, "utf8");
|
||||
}
|
||||
|
||||
export async function readMemoryHostEvents(params: {
|
||||
workspaceDir: string;
|
||||
limit?: number;
|
||||
}): Promise<MemoryHostEvent[]> {
|
||||
const eventLogPath = resolveMemoryHostEventLogPath(params.workspaceDir);
|
||||
const raw = await fs.readFile(eventLogPath, "utf8").catch((err: unknown) => {
|
||||
if ((err as NodeJS.ErrnoException)?.code === "ENOENT") {
|
||||
return "";
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
if (!raw.trim()) {
|
||||
return [];
|
||||
}
|
||||
const events = raw
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean)
|
||||
.flatMap((line) => {
|
||||
try {
|
||||
return [JSON.parse(line) as MemoryHostEvent];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
if (!Number.isFinite(params.limit)) {
|
||||
return events;
|
||||
}
|
||||
const limit = Math.max(0, Math.floor(params.limit as number));
|
||||
return limit === 0 ? [] : events.slice(-limit);
|
||||
}
|
||||
1
src/plugin-sdk/memory-core-host-events.ts
Normal file
1
src/plugin-sdk/memory-core-host-events.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "../memory-host-sdk/events.js";
|
||||
@@ -46,6 +46,12 @@ export {
|
||||
withProgress,
|
||||
withProgressTotals,
|
||||
} from "./memory-core-host-runtime-cli.js";
|
||||
export {
|
||||
appendMemoryHostEvent,
|
||||
readMemoryHostEvents,
|
||||
resolveMemoryHostEventLogPath,
|
||||
} from "./memory-core-host-events.js";
|
||||
export type { MemoryHostEvent } from "./memory-core-host-events.js";
|
||||
export {
|
||||
resolveMemoryCorePluginConfig,
|
||||
formatMemoryDreamingDay,
|
||||
|
||||
60
src/plugin-sdk/memory-host-events.test.ts
Normal file
60
src/plugin-sdk/memory-host-events.test.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
appendMemoryHostEvent,
|
||||
readMemoryHostEvents,
|
||||
resolveMemoryHostEventLogPath,
|
||||
} from "./memory-host-events.js";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })));
|
||||
});
|
||||
|
||||
describe("memory host event journal helpers", () => {
|
||||
it("appends and reads typed workspace events", async () => {
|
||||
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "memory-host-events-"));
|
||||
tempDirs.push(workspaceDir);
|
||||
|
||||
await appendMemoryHostEvent(workspaceDir, {
|
||||
type: "memory.recall.recorded",
|
||||
timestamp: "2026-04-05T12:00:00.000Z",
|
||||
query: "glacier backup",
|
||||
resultCount: 1,
|
||||
results: [
|
||||
{
|
||||
path: "memory/2026-04-05.md",
|
||||
startLine: 1,
|
||||
endLine: 3,
|
||||
score: 0.9,
|
||||
},
|
||||
],
|
||||
});
|
||||
await appendMemoryHostEvent(workspaceDir, {
|
||||
type: "memory.dream.completed",
|
||||
timestamp: "2026-04-05T13:00:00.000Z",
|
||||
phase: "light",
|
||||
lineCount: 4,
|
||||
storageMode: "both",
|
||||
inlinePath: path.join(workspaceDir, "memory", "2026-04-05.md"),
|
||||
reportPath: path.join(workspaceDir, "memory", "dreaming", "light", "2026-04-05.md"),
|
||||
});
|
||||
|
||||
const eventLogPath = resolveMemoryHostEventLogPath(workspaceDir);
|
||||
await expect(fs.readFile(eventLogPath, "utf8")).resolves.toContain(
|
||||
'"type":"memory.recall.recorded"',
|
||||
);
|
||||
|
||||
const events = await readMemoryHostEvents({ workspaceDir });
|
||||
const tail = await readMemoryHostEvents({ workspaceDir, limit: 1 });
|
||||
|
||||
expect(events).toHaveLength(2);
|
||||
expect(events[0]?.type).toBe("memory.recall.recorded");
|
||||
expect(events[1]?.type).toBe("memory.dream.completed");
|
||||
expect(tail).toHaveLength(1);
|
||||
expect(tail[0]?.type).toBe("memory.dream.completed");
|
||||
});
|
||||
});
|
||||
1
src/plugin-sdk/memory-host-events.ts
Normal file
1
src/plugin-sdk/memory-host-events.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "../memory-host-sdk/events.js";
|
||||
Reference in New Issue
Block a user