Spaces:
Paused
Paused
| import { describe, expect, it } from "vitest"; | |
| import { bm25RankToScore, buildFtsQuery, mergeHybridResults } from "./hybrid.js"; | |
| describe("memory hybrid helpers", () => { | |
| it("buildFtsQuery tokenizes and AND-joins", () => { | |
| expect(buildFtsQuery("hello world")).toBe('"hello" AND "world"'); | |
| expect(buildFtsQuery("FOO_bar baz-1")).toBe('"FOO_bar" AND "baz" AND "1"'); | |
| expect(buildFtsQuery(" ")).toBeNull(); | |
| }); | |
| it("bm25RankToScore is monotonic and clamped", () => { | |
| expect(bm25RankToScore(0)).toBeCloseTo(1); | |
| expect(bm25RankToScore(1)).toBeCloseTo(0.5); | |
| expect(bm25RankToScore(10)).toBeLessThan(bm25RankToScore(1)); | |
| expect(bm25RankToScore(-100)).toBeCloseTo(1); | |
| }); | |
| it("mergeHybridResults unions by id and combines weighted scores", () => { | |
| const merged = mergeHybridResults({ | |
| vectorWeight: 0.7, | |
| textWeight: 0.3, | |
| vector: [ | |
| { | |
| id: "a", | |
| path: "memory/a.md", | |
| startLine: 1, | |
| endLine: 2, | |
| source: "memory", | |
| snippet: "vec-a", | |
| vectorScore: 0.9, | |
| }, | |
| ], | |
| keyword: [ | |
| { | |
| id: "b", | |
| path: "memory/b.md", | |
| startLine: 3, | |
| endLine: 4, | |
| source: "memory", | |
| snippet: "kw-b", | |
| textScore: 1.0, | |
| }, | |
| ], | |
| }); | |
| expect(merged).toHaveLength(2); | |
| const a = merged.find((r) => r.path === "memory/a.md"); | |
| const b = merged.find((r) => r.path === "memory/b.md"); | |
| expect(a?.score).toBeCloseTo(0.7 * 0.9); | |
| expect(b?.score).toBeCloseTo(0.3 * 1.0); | |
| }); | |
| it("mergeHybridResults prefers keyword snippet when ids overlap", () => { | |
| const merged = mergeHybridResults({ | |
| vectorWeight: 0.5, | |
| textWeight: 0.5, | |
| vector: [ | |
| { | |
| id: "a", | |
| path: "memory/a.md", | |
| startLine: 1, | |
| endLine: 2, | |
| source: "memory", | |
| snippet: "vec-a", | |
| vectorScore: 0.2, | |
| }, | |
| ], | |
| keyword: [ | |
| { | |
| id: "a", | |
| path: "memory/a.md", | |
| startLine: 1, | |
| endLine: 2, | |
| source: "memory", | |
| snippet: "kw-a", | |
| textScore: 1.0, | |
| }, | |
| ], | |
| }); | |
| expect(merged).toHaveLength(1); | |
| expect(merged[0]?.snippet).toBe("kw-a"); | |
| expect(merged[0]?.score).toBeCloseTo(0.5 * 0.2 + 0.5 * 1.0); | |
| }); | |
| }); | |