sensemaking 0.18.2 → 0.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/status.js +32 -31
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/commands/map.js +50 -67
- package/dist/cjs/commands/map.js.map +1 -1
- package/dist/cjs/config/access.d.cts +2 -2
- package/dist/cjs/config/access.d.ts +2 -2
- package/dist/cjs/config/access.js.map +1 -1
- package/dist/cjs/config/index.d.cts +1 -1
- package/dist/cjs/config/index.d.ts +1 -1
- package/dist/cjs/config/index.js.map +1 -1
- package/dist/cjs/config/load.js +3 -2
- package/dist/cjs/config/load.js.map +1 -1
- package/dist/cjs/config/types.d.cts +2 -1
- package/dist/cjs/config/types.d.ts +2 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/config/validate.js +3 -0
- package/dist/cjs/config/validate.js.map +1 -1
- package/dist/cjs/embed/identity.js +3 -2
- package/dist/cjs/embed/identity.js.map +1 -1
- package/dist/cjs/embed/store.js +3 -3
- package/dist/cjs/embed/store.js.map +1 -1
- package/dist/cjs/index.d.cts +2 -2
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/atomic-write.d.cts +1 -0
- package/dist/cjs/lib/atomic-write.d.ts +1 -0
- package/dist/cjs/lib/atomic-write.js +26 -0
- package/dist/cjs/lib/atomic-write.js.map +1 -0
- package/dist/cjs/store/duckdb/batch.js +3 -2
- package/dist/cjs/store/duckdb/batch.js.map +1 -1
- package/dist/cjs/store/duckdb/connection.js +12 -0
- package/dist/cjs/store/duckdb/connection.js.map +1 -1
- package/dist/cjs/store/duckdb/fieldStats.d.cts +2 -0
- package/dist/cjs/store/duckdb/fieldStats.d.ts +2 -0
- package/dist/cjs/store/duckdb/fieldStats.js +219 -0
- package/dist/cjs/store/duckdb/fieldStats.js.map +1 -0
- package/dist/cjs/store/duckdb/lexical.js +16 -9
- package/dist/cjs/store/duckdb/lexical.js.map +1 -1
- package/dist/cjs/store/duckdb/native.d.cts +0 -1
- package/dist/cjs/store/duckdb/native.d.ts +0 -1
- package/dist/cjs/store/duckdb/native.js +7 -336
- package/dist/cjs/store/duckdb/native.js.map +1 -1
- package/dist/cjs/store/duckdb/sql-functions.js +1 -1
- package/dist/cjs/store/duckdb/sql-functions.js.map +1 -1
- package/dist/cjs/store/duckdb/store.js +16 -1
- package/dist/cjs/store/duckdb/store.js.map +1 -1
- package/dist/cjs/store/duckdb/vectors.js +5 -17
- package/dist/cjs/store/duckdb/vectors.js.map +1 -1
- package/dist/cjs/store/index.js +6 -0
- package/dist/cjs/store/index.js.map +1 -1
- package/dist/cjs/store/native.d.cts +7 -0
- package/dist/cjs/store/native.d.ts +7 -0
- package/dist/cjs/store/native.js +350 -0
- package/dist/cjs/store/native.js.map +1 -0
- package/dist/cjs/store/sqlite/fieldStats.d.cts +2 -0
- package/dist/cjs/store/sqlite/fieldStats.d.ts +2 -0
- package/dist/cjs/store/sqlite/fieldStats.js +201 -0
- package/dist/cjs/store/sqlite/fieldStats.js.map +1 -0
- package/dist/cjs/store/sqlite/open.js +82 -29
- package/dist/cjs/store/sqlite/open.js.map +1 -1
- package/dist/cjs/store/sqlite/store.js +32 -4
- package/dist/cjs/store/sqlite/store.js.map +1 -1
- package/dist/cjs/store/sqlite/vectors.d.cts +0 -5
- package/dist/cjs/store/sqlite/vectors.d.ts +0 -5
- package/dist/cjs/store/sqlite/vectors.js +5 -71
- package/dist/cjs/store/sqlite/vectors.js.map +1 -1
- package/dist/cjs/store/turso/connection.d.cts +3 -0
- package/dist/cjs/store/turso/connection.d.ts +3 -0
- package/dist/cjs/store/turso/connection.js +529 -0
- package/dist/cjs/store/turso/connection.js.map +1 -0
- package/dist/cjs/store/turso/fieldStats.d.cts +2 -0
- package/dist/cjs/store/turso/fieldStats.d.ts +2 -0
- package/dist/cjs/store/turso/fieldStats.js +201 -0
- package/dist/cjs/store/turso/fieldStats.js.map +1 -0
- package/dist/cjs/store/turso/native.d.cts +2 -0
- package/dist/cjs/store/turso/native.d.ts +2 -0
- package/dist/cjs/store/turso/native.js +31 -0
- package/dist/cjs/store/turso/native.js.map +1 -0
- package/dist/cjs/store/turso/open.d.cts +12 -0
- package/dist/cjs/store/turso/open.d.ts +12 -0
- package/dist/cjs/store/turso/open.js +500 -0
- package/dist/cjs/store/turso/open.js.map +1 -0
- package/dist/cjs/store/turso/reconcile.d.cts +6 -0
- package/dist/cjs/store/turso/reconcile.d.ts +6 -0
- package/dist/cjs/store/turso/reconcile.js +793 -0
- package/dist/cjs/store/turso/reconcile.js.map +1 -0
- package/dist/cjs/store/turso/store.d.cts +5 -0
- package/dist/cjs/store/turso/store.d.ts +5 -0
- package/dist/cjs/store/turso/store.js +609 -0
- package/dist/cjs/store/turso/store.js.map +1 -0
- package/dist/cjs/store/types.d.cts +9 -1
- package/dist/cjs/store/types.d.ts +9 -1
- package/dist/cjs/store/types.js +0 -7
- package/dist/cjs/store/types.js.map +1 -1
- package/dist/cjs/store/vectors.d.cts +9 -0
- package/dist/cjs/store/vectors.d.ts +9 -0
- package/dist/cjs/store/vectors.js +215 -0
- package/dist/cjs/store/vectors.js.map +1 -0
- package/dist/esm/cli/status.js +5 -7
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/commands/map.js +7 -19
- package/dist/esm/commands/map.js.map +1 -1
- package/dist/esm/config/access.d.ts +2 -2
- package/dist/esm/config/access.js.map +1 -1
- package/dist/esm/config/index.d.ts +1 -1
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/config/load.js +4 -3
- package/dist/esm/config/load.js.map +1 -1
- package/dist/esm/config/types.d.ts +2 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/config/validate.js +3 -0
- package/dist/esm/config/validate.js.map +1 -1
- package/dist/esm/embed/identity.js +4 -3
- package/dist/esm/embed/identity.js.map +1 -1
- package/dist/esm/embed/store.js +3 -3
- package/dist/esm/embed/store.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/atomic-write.d.ts +1 -0
- package/dist/esm/lib/atomic-write.js +17 -0
- package/dist/esm/lib/atomic-write.js.map +1 -0
- package/dist/esm/store/duckdb/batch.js +3 -2
- package/dist/esm/store/duckdb/batch.js.map +1 -1
- package/dist/esm/store/duckdb/connection.js +12 -0
- package/dist/esm/store/duckdb/connection.js.map +1 -1
- package/dist/esm/store/duckdb/fieldStats.d.ts +2 -0
- package/dist/esm/store/duckdb/fieldStats.js +39 -0
- package/dist/esm/store/duckdb/fieldStats.js.map +1 -0
- package/dist/esm/store/duckdb/lexical.js +19 -9
- package/dist/esm/store/duckdb/lexical.js.map +1 -1
- package/dist/esm/store/duckdb/native.d.ts +0 -1
- package/dist/esm/store/duckdb/native.js +7 -84
- package/dist/esm/store/duckdb/native.js.map +1 -1
- package/dist/esm/store/duckdb/sql-functions.js +1 -1
- package/dist/esm/store/duckdb/sql-functions.js.map +1 -1
- package/dist/esm/store/duckdb/store.js +8 -5
- package/dist/esm/store/duckdb/store.js.map +1 -1
- package/dist/esm/store/duckdb/vectors.js +2 -12
- package/dist/esm/store/duckdb/vectors.js.map +1 -1
- package/dist/esm/store/index.js +6 -0
- package/dist/esm/store/index.js.map +1 -1
- package/dist/esm/store/native.d.ts +7 -0
- package/dist/esm/store/native.js +83 -0
- package/dist/esm/store/native.js.map +1 -0
- package/dist/esm/store/sqlite/fieldStats.d.ts +2 -0
- package/dist/esm/store/sqlite/fieldStats.js +25 -0
- package/dist/esm/store/sqlite/fieldStats.js.map +1 -0
- package/dist/esm/store/sqlite/open.js +21 -8
- package/dist/esm/store/sqlite/open.js.map +1 -1
- package/dist/esm/store/sqlite/store.js +14 -1
- package/dist/esm/store/sqlite/store.js.map +1 -1
- package/dist/esm/store/sqlite/vectors.d.ts +0 -5
- package/dist/esm/store/sqlite/vectors.js +2 -22
- package/dist/esm/store/sqlite/vectors.js.map +1 -1
- package/dist/esm/store/turso/connection.d.ts +3 -0
- package/dist/esm/store/turso/connection.js +52 -0
- package/dist/esm/store/turso/connection.js.map +1 -0
- package/dist/esm/store/turso/fieldStats.d.ts +2 -0
- package/dist/esm/store/turso/fieldStats.js +24 -0
- package/dist/esm/store/turso/fieldStats.js.map +1 -0
- package/dist/esm/store/turso/native.d.ts +2 -0
- package/dist/esm/store/turso/native.js +19 -0
- package/dist/esm/store/turso/native.js.map +1 -0
- package/dist/esm/store/turso/open.d.ts +12 -0
- package/dist/esm/store/turso/open.js +113 -0
- package/dist/esm/store/turso/open.js.map +1 -0
- package/dist/esm/store/turso/reconcile.d.ts +6 -0
- package/dist/esm/store/turso/reconcile.js +158 -0
- package/dist/esm/store/turso/reconcile.js.map +1 -0
- package/dist/esm/store/turso/store.d.ts +5 -0
- package/dist/esm/store/turso/store.js +93 -0
- package/dist/esm/store/turso/store.js.map +1 -0
- package/dist/esm/store/types.d.ts +9 -1
- package/dist/esm/store/types.js +0 -7
- package/dist/esm/store/types.js.map +1 -1
- package/dist/esm/store/vectors.d.ts +9 -0
- package/dist/esm/store/vectors.js +26 -0
- package/dist/esm/store/vectors.js.map +1 -0
- package/package.json +2 -1
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import type { Connection, VectorCandidate, VectorSimilar, VectorWriteRow } from '../types.js';
|
|
2
|
-
export declare function pendingRows(conn: Connection): Promise<Array<{
|
|
3
|
-
path: string;
|
|
4
|
-
chunk: number;
|
|
5
|
-
}>>;
|
|
6
2
|
export declare function writeVectorBatch(conn: Connection, rows: VectorWriteRow[]): Promise<void>;
|
|
7
3
|
export declare function scanCandidates(conn: Connection, qv: Float32Array, storeDims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]>;
|
|
8
4
|
export declare function scanSimilar(conn: Connection, path: string, opts: {
|
|
@@ -10,4 +6,3 @@ export declare function scanSimilar(conn: Connection, path: string, opts: {
|
|
|
10
6
|
allowed?: Set<string>;
|
|
11
7
|
k: number;
|
|
12
8
|
}): Promise<VectorSimilar[]>;
|
|
13
|
-
export declare function hasVectorRow(conn: Connection, path: string): Promise<boolean>;
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import type { Connection, VectorCandidate, VectorSimilar, VectorWriteRow } from '../types.js';
|
|
2
|
-
export declare function pendingRows(conn: Connection): Promise<Array<{
|
|
3
|
-
path: string;
|
|
4
|
-
chunk: number;
|
|
5
|
-
}>>;
|
|
6
2
|
export declare function writeVectorBatch(conn: Connection, rows: VectorWriteRow[]): Promise<void>;
|
|
7
3
|
export declare function scanCandidates(conn: Connection, qv: Float32Array, storeDims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]>;
|
|
8
4
|
export declare function scanSimilar(conn: Connection, path: string, opts: {
|
|
@@ -10,4 +6,3 @@ export declare function scanSimilar(conn: Connection, path: string, opts: {
|
|
|
10
6
|
allowed?: Set<string>;
|
|
11
7
|
k: number;
|
|
12
8
|
}): Promise<VectorSimilar[]>;
|
|
13
|
-
export declare function hasVectorRow(conn: Connection, path: string): Promise<boolean>;
|
|
@@ -9,12 +9,6 @@ function _export(target, all) {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
_export(exports, {
|
|
12
|
-
get hasVectorRow () {
|
|
13
|
-
return hasVectorRow;
|
|
14
|
-
},
|
|
15
|
-
get pendingRows () {
|
|
16
|
-
return pendingRows;
|
|
17
|
-
},
|
|
18
12
|
get scanCandidates () {
|
|
19
13
|
return scanCandidates;
|
|
20
14
|
},
|
|
@@ -25,6 +19,7 @@ _export(exports, {
|
|
|
25
19
|
return writeVectorBatch;
|
|
26
20
|
}
|
|
27
21
|
});
|
|
22
|
+
var _vectorsts = require("../vectors.js");
|
|
28
23
|
function _array_like_to_array(arr, len) {
|
|
29
24
|
if (len == null || len > arr.length) len = arr.length;
|
|
30
25
|
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
@@ -210,38 +205,6 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
210
205
|
if (n === "Map" || n === "Set") return Array.from(n);
|
|
211
206
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
212
207
|
}
|
|
213
|
-
// Seed chunks that participate in a `related` scan; see similar() for the measurement.
|
|
214
|
-
var TARGET_CHUNK_CAP = 16;
|
|
215
|
-
// Dequantised int8 dot products land a little either side of a true cosine, so an identical
|
|
216
|
-
// pair prints 1.001 and undermines a column whose whole job is being a bounded number.
|
|
217
|
-
function asCosine(score) {
|
|
218
|
-
return Math.round(Math.min(1, Math.max(-1, score)) * 1000) / 1000;
|
|
219
|
-
}
|
|
220
|
-
function pendingRows(conn) {
|
|
221
|
-
return _async_to_generator(function() {
|
|
222
|
-
var stmt;
|
|
223
|
-
return _ts_generator(this, function(_state) {
|
|
224
|
-
switch(_state.label){
|
|
225
|
-
case 0:
|
|
226
|
-
return [
|
|
227
|
-
4,
|
|
228
|
-
conn.prepare('SELECT "path", chunk FROM embeddings WHERE vector IS NULL ORDER BY "path", chunk')
|
|
229
|
-
];
|
|
230
|
-
case 1:
|
|
231
|
-
stmt = _state.sent();
|
|
232
|
-
return [
|
|
233
|
-
4,
|
|
234
|
-
stmt.all()
|
|
235
|
-
];
|
|
236
|
-
case 2:
|
|
237
|
-
return [
|
|
238
|
-
2,
|
|
239
|
-
_state.sent()
|
|
240
|
-
];
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
})();
|
|
244
|
-
}
|
|
245
208
|
function writeVectorBatch(conn, rows) {
|
|
246
209
|
return _async_to_generator(function() {
|
|
247
210
|
return _ts_generator(this, function(_state) {
|
|
@@ -327,7 +290,7 @@ function scanCandidates(conn, qv, storeDims, fetch, allowed) {
|
|
|
327
290
|
return {
|
|
328
291
|
path: path,
|
|
329
292
|
lines: b.lines,
|
|
330
|
-
similarity: asCosine(b.score)
|
|
293
|
+
similarity: (0, _vectorsts.asCosine)(b.score)
|
|
331
294
|
};
|
|
332
295
|
})
|
|
333
296
|
];
|
|
@@ -337,7 +300,7 @@ function scanCandidates(conn, qv, storeDims, fetch, allowed) {
|
|
|
337
300
|
}
|
|
338
301
|
function scanSimilar(conn, path, opts) {
|
|
339
302
|
return _async_to_generator(function() {
|
|
340
|
-
var targetStmt, targetRows,
|
|
303
|
+
var targetStmt, targetRows, target, stmt, rows, best, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, row, other, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, t, dot, len, d, score, existing;
|
|
341
304
|
return _ts_generator(this, function(_state) {
|
|
342
305
|
switch(_state.label){
|
|
343
306
|
case 0:
|
|
@@ -357,10 +320,7 @@ function scanSimilar(conn, path, opts) {
|
|
|
357
320
|
2,
|
|
358
321
|
[]
|
|
359
322
|
];
|
|
360
|
-
|
|
361
|
-
target = targetRows.filter(function(_, i) {
|
|
362
|
-
return i % step === 0;
|
|
363
|
-
}).map(function(row) {
|
|
323
|
+
target = (0, _vectorsts.sampleEvenly)(targetRows).map(function(row) {
|
|
364
324
|
return {
|
|
365
325
|
v: new Int8Array(row.vector.buffer, row.vector.byteOffset, row.vector.byteLength),
|
|
366
326
|
scale: row.scale
|
|
@@ -433,7 +393,7 @@ function scanSimilar(conn, path, opts) {
|
|
|
433
393
|
var _param = _sliced_to_array(param, 2), p = _param[0], score = _param[1];
|
|
434
394
|
return {
|
|
435
395
|
path: p,
|
|
436
|
-
similarity: asCosine(score)
|
|
396
|
+
similarity: (0, _vectorsts.asCosine)(score)
|
|
437
397
|
};
|
|
438
398
|
})
|
|
439
399
|
];
|
|
@@ -441,30 +401,4 @@ function scanSimilar(conn, path, opts) {
|
|
|
441
401
|
});
|
|
442
402
|
})();
|
|
443
403
|
}
|
|
444
|
-
function hasVectorRow(conn, path) {
|
|
445
|
-
return _async_to_generator(function() {
|
|
446
|
-
var stmt, row;
|
|
447
|
-
return _ts_generator(this, function(_state) {
|
|
448
|
-
switch(_state.label){
|
|
449
|
-
case 0:
|
|
450
|
-
return [
|
|
451
|
-
4,
|
|
452
|
-
conn.prepare('SELECT 1 AS ok FROM embeddings WHERE "path" = ? AND vector IS NOT NULL LIMIT 1')
|
|
453
|
-
];
|
|
454
|
-
case 1:
|
|
455
|
-
stmt = _state.sent();
|
|
456
|
-
return [
|
|
457
|
-
4,
|
|
458
|
-
stmt.get(path)
|
|
459
|
-
];
|
|
460
|
-
case 2:
|
|
461
|
-
row = _state.sent();
|
|
462
|
-
return [
|
|
463
|
-
2,
|
|
464
|
-
row !== undefined
|
|
465
|
-
];
|
|
466
|
-
}
|
|
467
|
-
});
|
|
468
|
-
})();
|
|
469
|
-
}
|
|
470
404
|
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/sqlite/vectors.ts"],"sourcesContent":["import type { Connection, VectorCandidate, VectorSimilar, VectorWriteRow } from '../types.ts';\n\n// Seed chunks that participate in a `related` scan; see similar() for the measurement.\nconst TARGET_CHUNK_CAP = 16;\n\n// Dequantised int8 dot products land a little either side of a true cosine, so an identical\n// pair prints 1.001 and undermines a column whose whole job is being a bounded number.\nfunction asCosine(score: number): number {\n return Math.round(Math.min(1, Math.max(-1, score)) * 1000) / 1000;\n}\n\nexport async function pendingRows(conn: Connection): Promise<Array<{ path: string; chunk: number }>> {\n const stmt = await conn.prepare('SELECT \"path\", chunk FROM embeddings WHERE vector IS NULL ORDER BY \"path\", chunk');\n return (await stmt.all()) as Array<{ path: string; chunk: number }>;\n}\n\n// One runBatch call per provider batch: the caller (embed/query.ts) already batches by the\n// provider's batchCap, so this is one crossing per batch, never per row.\nexport async function writeVectorBatch(conn: Connection, rows: VectorWriteRow[]): Promise<void> {\n if (rows.length === 0) return;\n await conn.runBatch(\n 'UPDATE embeddings SET scale = ?, vector = ? WHERE \"path\" = ? AND chunk = ?',\n rows.map((row) => [row.scale, row.vector, row.path, row.chunk])\n );\n}\n\n// Best chunk per file by cosine, its line range riding along: the JS loop over stored int8\n// BLOBs this store's scan strategy is (a native store scans differently, same contract).\nexport async function scanCandidates(conn: Connection, qv: Float32Array, storeDims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]> {\n const stmt = await conn.prepare('SELECT \"path\", start_line, end_line, scale, vector FROM embeddings WHERE vector IS NOT NULL');\n const rows = (await stmt.all()) as Array<{\n path: string;\n start_line: number;\n end_line: number;\n scale: number;\n vector: Uint8Array;\n }>;\n\n const best = new Map<string, { score: number; lines: string }>();\n for (const row of rows) {\n if (allowed && !allowed.has(row.path)) continue;\n const q = new Int8Array(row.vector.buffer, row.vector.byteOffset, Math.min(storeDims, row.vector.byteLength));\n let dot = 0;\n for (let d = 0; d < q.length; d++) dot += q[d] * qv[d];\n const score = dot * row.scale;\n const existing = best.get(row.path);\n if (!existing || score > existing.score) best.set(row.path, { score, lines: `L${row.start_line}-${row.end_line}` });\n }\n return [...best.entries()]\n .sort((a, b) => b[1].score - a[1].score)\n .slice(0, fetch)\n .map(([path, b]) => ({ path, lines: b.lines, similarity: asCosine(b.score) }));\n}\n\n// Note-to-note similarity is the max cosine over (target chunk, other chunk) pairs, one linear\n// scan of stored vectors.\nexport async function scanSimilar(conn: Connection, path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]> {\n // Cost is target_chunks x stored_chunks, so a heading-dense seed multiplies a full-corpus\n // scan (12.7s at 201 chunks/note). Sample evenly, so late sections still get a vote.\n const targetStmt = await conn.prepare('SELECT scale, vector FROM embeddings WHERE \"path\" = ? AND vector IS NOT NULL ORDER BY chunk');\n const targetRows = (await targetStmt.all(path)) as Array<{ scale: number; vector: Uint8Array }>;\n if (targetRows.length === 0) return [];\n const step = Math.max(1, Math.ceil(targetRows.length / TARGET_CHUNK_CAP));\n const target = targetRows.filter((_, i) => i % step === 0).map((row) => ({ v: new Int8Array(row.vector.buffer, row.vector.byteOffset, row.vector.byteLength), scale: row.scale }));\n\n const stmt = await conn.prepare('SELECT \"path\", scale, vector FROM embeddings WHERE vector IS NOT NULL');\n const rows = (await stmt.all()) as Array<{ path: string; scale: number; vector: Uint8Array }>;\n const best = new Map<string, number>();\n for (const row of rows) {\n if (row.path === path || opts.exclude.has(row.path) || (opts.allowed && !opts.allowed.has(row.path))) continue;\n const other = new Int8Array(row.vector.buffer, row.vector.byteOffset, row.vector.byteLength);\n for (const t of target) {\n let dot = 0;\n const len = Math.min(t.v.length, other.length);\n for (let d = 0; d < len; d++) dot += t.v[d] * other[d];\n const score = dot * t.scale * row.scale;\n const existing = best.get(row.path);\n if (existing === undefined || score > existing) best.set(row.path, score);\n }\n }\n\n return [...best.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, opts.k)\n .map(([p, score]) => ({ path: p, similarity: asCosine(score) }));\n}\n\n// Whether a note has any chunk with a vector. Distinguishes \"nothing is near this note\" from\n// \"this note has no text\", which look the same in an empty result.\nexport async function hasVectorRow(conn: Connection, path: string): Promise<boolean> {\n const stmt = await conn.prepare('SELECT 1 AS ok FROM embeddings WHERE \"path\" = ? AND vector IS NOT NULL LIMIT 1');\n const row = (await stmt.get(path)) as { ok: number } | undefined;\n return row !== undefined;\n}\n"],"names":["hasVectorRow","pendingRows","scanCandidates","scanSimilar","writeVectorBatch","TARGET_CHUNK_CAP","asCosine","score","Math","round","min","max","conn","stmt","prepare","all","rows","length","runBatch","map","row","scale","vector","path","chunk","qv","storeDims","fetch","allowed","best","q","dot","d","existing","Map","has","Int8Array","buffer","byteOffset","byteLength","get","set","lines","start_line","end_line","entries","sort","a","b","slice","similarity","opts","targetStmt","targetRows","step","target","other","t","len","ceil","filter","_","i","v","exclude","undefined","k","p"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/sqlite/vectors.ts"],"sourcesContent":["import type { Connection, VectorCandidate, VectorSimilar, VectorWriteRow } from '../types.ts';\nimport { asCosine, sampleEvenly } from '../vectors.ts';\n\n// One runBatch call per provider batch: the caller (embed/query.ts) already batches by the\n// provider's batchCap, so this is one crossing per batch, never per row.\nexport async function writeVectorBatch(conn: Connection, rows: VectorWriteRow[]): Promise<void> {\n if (rows.length === 0) return;\n await conn.runBatch(\n 'UPDATE embeddings SET scale = ?, vector = ? WHERE \"path\" = ? AND chunk = ?',\n rows.map((row) => [row.scale, row.vector, row.path, row.chunk])\n );\n}\n\n// Best chunk per file by cosine, its line range riding along: the JS loop over stored int8\n// BLOBs this store's scan strategy is (a native store scans differently, same contract).\nexport async function scanCandidates(conn: Connection, qv: Float32Array, storeDims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]> {\n const stmt = await conn.prepare('SELECT \"path\", start_line, end_line, scale, vector FROM embeddings WHERE vector IS NOT NULL');\n const rows = (await stmt.all()) as Array<{\n path: string;\n start_line: number;\n end_line: number;\n scale: number;\n vector: Uint8Array;\n }>;\n\n const best = new Map<string, { score: number; lines: string }>();\n for (const row of rows) {\n if (allowed && !allowed.has(row.path)) continue;\n const q = new Int8Array(row.vector.buffer, row.vector.byteOffset, Math.min(storeDims, row.vector.byteLength));\n let dot = 0;\n for (let d = 0; d < q.length; d++) dot += q[d] * qv[d];\n const score = dot * row.scale;\n const existing = best.get(row.path);\n if (!existing || score > existing.score) best.set(row.path, { score, lines: `L${row.start_line}-${row.end_line}` });\n }\n return [...best.entries()]\n .sort((a, b) => b[1].score - a[1].score)\n .slice(0, fetch)\n .map(([path, b]) => ({ path, lines: b.lines, similarity: asCosine(b.score) }));\n}\n\n// Note-to-note similarity is the max cosine over (target chunk, other chunk) pairs, one linear\n// scan of stored vectors.\nexport async function scanSimilar(conn: Connection, path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]> {\n const targetStmt = await conn.prepare('SELECT scale, vector FROM embeddings WHERE \"path\" = ? AND vector IS NOT NULL ORDER BY chunk');\n const targetRows = (await targetStmt.all(path)) as Array<{ scale: number; vector: Uint8Array }>;\n if (targetRows.length === 0) return [];\n const target = sampleEvenly(targetRows).map((row) => ({ v: new Int8Array(row.vector.buffer, row.vector.byteOffset, row.vector.byteLength), scale: row.scale }));\n\n const stmt = await conn.prepare('SELECT \"path\", scale, vector FROM embeddings WHERE vector IS NOT NULL');\n const rows = (await stmt.all()) as Array<{ path: string; scale: number; vector: Uint8Array }>;\n const best = new Map<string, number>();\n for (const row of rows) {\n if (row.path === path || opts.exclude.has(row.path) || (opts.allowed && !opts.allowed.has(row.path))) continue;\n const other = new Int8Array(row.vector.buffer, row.vector.byteOffset, row.vector.byteLength);\n for (const t of target) {\n let dot = 0;\n const len = Math.min(t.v.length, other.length);\n for (let d = 0; d < len; d++) dot += t.v[d] * other[d];\n const score = dot * t.scale * row.scale;\n const existing = best.get(row.path);\n if (existing === undefined || score > existing) best.set(row.path, score);\n }\n }\n\n return [...best.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, opts.k)\n .map(([p, score]) => ({ path: p, similarity: asCosine(score) }));\n}\n"],"names":["scanCandidates","scanSimilar","writeVectorBatch","conn","rows","length","runBatch","map","row","scale","vector","path","chunk","qv","storeDims","fetch","allowed","stmt","best","q","dot","d","score","existing","prepare","all","Map","has","Int8Array","buffer","byteOffset","Math","min","byteLength","get","set","lines","start_line","end_line","entries","sort","a","b","slice","similarity","asCosine","opts","targetStmt","targetRows","target","other","t","len","sampleEvenly","v","exclude","undefined","k","p"],"mappings":"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"}
|