deskpaw-memory/test/timeline.test.js

30 lines
1.8 KiB
JavaScript

import { DatabaseSync } from "node:sqlite";
import { test } from "node:test";
import assert from "node:assert/strict";
import { Timeline } from "../src/timeline.js";
test("timeline is idempotent, indexed across old history, bounded and expandable", () => {
const db = new DatabaseSync(":memory:"); const timeline = new Timeline(db);
try {
timeline.append({ id: "old", kind: "user", at: 1, text: "财务报销会议" + "材料".repeat(1000), source: { channel: "feishu", sender: "A" } });
timeline.append({ id: "old", kind: "user", at: 2, text: "overwrite", source: {} });
for (let i = 0; i < 250; i++) timeline.append({ id: `new-${i}`, kind: "assistant", at: i + 2, text: "other", source: {} });
const result = timeline.query({ query: "报销", limit: 5 });
assert.equal(result.entries[0].id, "old"); assert.equal(result.embedding, false);
assert.equal(result.entries[0].expandable, true); assert.equal(timeline.read({ id: "old" }).at, 1);
assert.equal(timeline.read({ id: "old", offset: 0, limit: 2 }).text, "财务");
assert.equal(timeline.query({ from: 2, to: 2 }).entries.length, 1);
assert.throws(() => timeline.query({ limit: 999 }));
timeline.append({ id: "tail", kind: "user", at: 500, text: "padding ".repeat(2500) + "uniqueTail", source: {} });
assert.equal(timeline.query({ query: "uniqueTail" }).entries[0].id, "tail");
} finally { db.close(); }
});
test("timeline excludes secrets and rejects unbounded data", () => {
const db = new DatabaseSync(":memory:"); const timeline = new Timeline(db);
try {
timeline.append({ id: "secret", kind: "user", at: 1, text: "password=example", source: {} });
assert.equal(timeline.read({ id: "secret" }).text, "[敏感内容未写入记忆]");
assert.throws(() => timeline.append({ id: "large", kind: "user", at: 1, text: "x".repeat(32001) }));
} finally { db.close(); }
});