vector-store-sqlite.test.mjs
148 lines 4.3 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * SQLite vector store tests: ensureCollection, upsert, search, count, close.
3 * Uses a temp directory for the DB.
4 */
5 import { describe, it, before, after } from 'node:test';
6 import assert from 'node:assert';
7 import path from 'path';
8 import fs from 'fs';
9 import { fileURLToPath } from 'url';
10 import { createSqliteVectorStore } from '../lib/vector-store-sqlite.mjs';
11
12 const __dirname = path.dirname(fileURLToPath(import.meta.url));
13 const testDataDir = path.join(__dirname, 'fixtures', 'tmp-vector-db');
14
15 describe('vector-store-sqlite', () => {
16 let store;
17
18 before(() => {
19 if (fs.existsSync(testDataDir)) {
20 fs.rmSync(testDataDir, { recursive: true });
21 }
22 fs.mkdirSync(testDataDir, { recursive: true });
23 store = createSqliteVectorStore({ data_dir: testDataDir });
24 });
25
26 after(() => {
27 if (store && typeof store.close === 'function') store.close();
28 if (fs.existsSync(testDataDir)) {
29 try {
30 fs.rmSync(testDataDir, { recursive: true });
31 } catch (_) {}
32 }
33 });
34
35 it('ensureCollection creates table with given dimension', async () => {
36 await store.ensureCollection(3);
37 const count = await store.count();
38 assert.strictEqual(count, 0);
39 });
40
41 it('ensureCollection throws when table exists with different dimension', async () => {
42 await assert.rejects(
43 () => store.ensureCollection(5),
44 /dimension mismatch/
45 );
46 });
47
48 it('upsert inserts points and count increases', async () => {
49 await store.upsert([
50 {
51 id: 'path/to/a_0',
52 vector: [0.1, 0.2, 0.3],
53 path: 'path/to/a.md',
54 project: 'p',
55 date: '2025-03-01',
56 tags: ['t1'],
57 text: 'chunk one',
58 },
59 {
60 id: 'path/to/b_0',
61 vector: [0.4, 0.5, 0.6],
62 path: 'path/to/b.md',
63 project: 'p',
64 date: '2025-03-02',
65 tags: [],
66 text: 'chunk two',
67 },
68 ]);
69 const count = await store.count();
70 assert.strictEqual(count, 2);
71 });
72
73 it('upsert same chunk id again replaces row (vec0 has no INSERT OR REPLACE)', async () => {
74 await store.upsert([
75 {
76 id: 'path/to/a_0',
77 vector: [0.11, 0.21, 0.31],
78 path: 'path/to/a.md',
79 project: 'p',
80 date: '2025-03-01',
81 tags: ['t1'],
82 text: 'replaced chunk',
83 },
84 ]);
85 const count = await store.count();
86 assert.strictEqual(count, 2);
87 const hits = await store.search([0.11, 0.21, 0.31], { limit: 5 });
88 const a = hits.find((h) => h.path === 'path/to/a.md');
89 assert(a && a.text === 'replaced chunk');
90 });
91
92 it('search returns hits with path, score, text', async () => {
93 const hits = await store.search([0.15, 0.25, 0.35], { limit: 5 });
94 assert(Array.isArray(hits));
95 assert(hits.length >= 1);
96 const first = hits[0];
97 assert(first.path);
98 assert(typeof first.score === 'number');
99 assert(first.score > 0, 'score must be positive (1/(1+distance)); L2 distances used to map to 0');
100 assert(first.text != null);
101 });
102
103 it('search filters by vault_id so multi-vault indexes do not leak paths', async () => {
104 const dim = 3;
105 const dir = path.join(testDataDir, 'vault-filter-sub');
106 fs.mkdirSync(dir, { recursive: true });
107 const vStore = createSqliteVectorStore({ data_dir: dir });
108 await vStore.ensureCollection(dim);
109 const vA = [1, 0, 0];
110 const vB = [0, 1, 0];
111 await vStore.upsert([
112 {
113 id: 'vault-a::same_0',
114 vector: vA,
115 path: 'same.md',
116 vault_id: 'vault-a',
117 project: null,
118 date: null,
119 tags: [],
120 text: 'alpha',
121 },
122 {
123 id: 'vault-b::same_0',
124 vector: vB,
125 path: 'same.md',
126 vault_id: 'vault-b',
127 project: null,
128 date: null,
129 tags: [],
130 text: 'beta',
131 },
132 ]);
133 const forA = await vStore.search(vA, { limit: 5, vault_id: 'vault-a' });
134 const forB = await vStore.search(vB, { limit: 5, vault_id: 'vault-b' });
135 assert.strictEqual(forA.length, 1);
136 assert.strictEqual(forA[0].text, 'alpha');
137 assert.strictEqual(forB.length, 1);
138 assert.strictEqual(forB[0].text, 'beta');
139 const noFilter = await vStore.search(vA, { limit: 10 });
140 assert.strictEqual(noFilter.length, 2);
141 vStore.close();
142 fs.rmSync(dir, { recursive: true });
143 });
144
145 it('has close() method for cleanup', () => {
146 assert.strictEqual(typeof store.close, 'function');
147 });
148 });
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago