Files
rohitg00--agentmemory/test/remember-bm25-index.test.ts
wehub-resource-sync 979fb22d7c
CI / test (20, macos-latest) (push) Has been cancelled
CI / test (20, ubuntu-latest) (push) Has been cancelled
CI / test (22, macos-latest) (push) Has been cancelled
CI / test (22, ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:01:18 +08:00

98 lines
3.1 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { SearchIndex } from "../src/state/search-index.js";
import type { CompressedObservation, Memory } from "../src/types.js";
// Mirrors the helper used by remember.ts and rebuildIndex(). Kept inline
// here rather than exporting from src/ so the test asserts the contract,
// not the implementation.
function memoryAsIndexable(memory: Memory): CompressedObservation {
return {
id: memory.id,
sessionId: memory.sessionIds[0] ?? "memory",
timestamp: memory.createdAt,
type: "decision",
title: memory.title,
facts: [memory.content],
narrative: memory.content,
concepts: memory.concepts,
files: memory.files,
importance: memory.strength,
};
}
function makeMemory(overrides: Partial<Memory> = {}): Memory {
return {
id: "mem_test_001",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
type: "fact",
title: "BM25 test memory",
content: "BM25 search returns this memory by keyword match",
concepts: ["bm25", "search", "test"],
files: [],
sessionIds: [],
strength: 7,
version: 1,
isLatest: true,
...overrides,
};
}
describe("SearchIndex.has()", () => {
it("returns false for unknown ids", () => {
expect(new SearchIndex().has("mem_unknown")).toBe(false);
});
it("returns true after add()", () => {
const idx = new SearchIndex();
idx.add(memoryAsIndexable(makeMemory()));
expect(idx.has("mem_test_001")).toBe(true);
});
});
describe("memory indexing into SearchIndex (closes #257)", () => {
it("makes a saved memory findable by keyword search", () => {
const idx = new SearchIndex();
idx.add(memoryAsIndexable(makeMemory({
id: "mem_user_001",
title: "JWT middleware uses jose for Edge compatibility",
content: "Chose jose over jsonwebtoken because Cloudflare Workers don't ship Node crypto",
concepts: ["auth", "jose", "edge"],
})));
const hits = idx.search("jose middleware", 5);
expect(hits).toHaveLength(1);
expect(hits[0].obsId).toBe("mem_user_001");
});
it("returns the memory when the issue's reproduction query is run", () => {
// From issue #257: user saved a memory containing 'BM25 test'
// keywords and the search returned empty — recall failure.
const idx = new SearchIndex();
idx.add(memoryAsIndexable(makeMemory({
id: "mem_moy3u6ua_8c6962b668e7",
title: "BM25 test",
content: "Confirmed BM25 indexing works for memories saved via memory_save",
concepts: [],
})));
const hits = idx.search("BM25 test", 5);
expect(hits.length).toBeGreaterThan(0);
expect(hits[0].obsId).toBe("mem_moy3u6ua_8c6962b668e7");
});
it("matches concepts as well as title and content", () => {
const idx = new SearchIndex();
idx.add(memoryAsIndexable(makeMemory({
id: "mem_concept_001",
title: "Generic title",
content: "Generic content",
concepts: ["unique-concept-marker"],
})));
const hits = idx.search("unique-concept-marker", 5);
expect(hits.length).toBeGreaterThan(0);
expect(hits[0].obsId).toBe("mem_concept_001");
});
});