@voidwire/lore 0.6.0 → 0.6.1
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/lib/list.ts +20 -15
- package/lib/projects.ts +1 -1
- package/lib/semantic.ts +27 -55
- package/package.json +1 -1
package/lib/list.ts
CHANGED
|
@@ -71,7 +71,7 @@ const PROJECT_FIELD: Record<string, string> = {
|
|
|
71
71
|
commits: "project",
|
|
72
72
|
sessions: "project",
|
|
73
73
|
tasks: "project",
|
|
74
|
-
insights: "
|
|
74
|
+
insights: "topic",
|
|
75
75
|
captures: "topic",
|
|
76
76
|
teachings: "topic",
|
|
77
77
|
learnings: "topic",
|
|
@@ -161,23 +161,28 @@ function queryPersonalType(
|
|
|
161
161
|
type: string,
|
|
162
162
|
limit?: number,
|
|
163
163
|
): ListEntry[] {
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
// Filter by type in SQL, not JS - avoids LIMIT truncation bug
|
|
165
|
+
let sql = `
|
|
166
|
+
SELECT title, content, metadata FROM search
|
|
167
|
+
WHERE source = 'personal'
|
|
168
|
+
AND json_extract(metadata, '$.type') = ?
|
|
169
|
+
ORDER BY json_extract(metadata, '$.timestamp') DESC
|
|
170
|
+
`;
|
|
171
|
+
const params: (string | number)[] = [type];
|
|
168
172
|
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
if (limit) {
|
|
174
|
+
sql += " LIMIT ?";
|
|
175
|
+
params.push(limit);
|
|
176
|
+
}
|
|
171
177
|
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
title: row.title,
|
|
175
|
-
content: row.content,
|
|
176
|
-
metadata: JSON.parse(row.metadata || "{}"),
|
|
177
|
-
}))
|
|
178
|
-
.filter((entry) => entry.metadata.type === type);
|
|
178
|
+
const stmt = db.prepare(sql);
|
|
179
|
+
const rows = stmt.all(...params) as RawRow[];
|
|
179
180
|
|
|
180
|
-
return
|
|
181
|
+
return rows.map((row) => ({
|
|
182
|
+
title: row.title,
|
|
183
|
+
content: row.content,
|
|
184
|
+
metadata: JSON.parse(row.metadata || "{}"),
|
|
185
|
+
}));
|
|
181
186
|
}
|
|
182
187
|
|
|
183
188
|
/**
|
package/lib/projects.ts
CHANGED
package/lib/semantic.ts
CHANGED
|
@@ -43,7 +43,7 @@ const PROJECT_FIELD: Record<string, string> = {
|
|
|
43
43
|
commits: "project",
|
|
44
44
|
sessions: "project",
|
|
45
45
|
tasks: "project",
|
|
46
|
-
insights: "
|
|
46
|
+
insights: "topic",
|
|
47
47
|
captures: "topic",
|
|
48
48
|
teachings: "topic",
|
|
49
49
|
learnings: "topic",
|
|
@@ -193,70 +193,42 @@ export async function semanticSearch(
|
|
|
193
193
|
|
|
194
194
|
// KNN query - 1:1 mapping between search rows and embeddings
|
|
195
195
|
// Content is pre-chunked at ingest time
|
|
196
|
+
// source/topic partition columns enable filtered KNN (filter BEFORE search)
|
|
196
197
|
let sql: string;
|
|
197
198
|
const params: (Uint8Array | string | number)[] = [queryBlob];
|
|
198
199
|
|
|
200
|
+
// Build KNN query with optional partition filters
|
|
201
|
+
const conditions = ["e.embedding MATCH ?", "k = ?"];
|
|
202
|
+
params.push(limit);
|
|
203
|
+
|
|
199
204
|
if (options.source) {
|
|
200
|
-
|
|
201
|
-
// This filters BEFORE KNN, not after — critical for domain-specific search
|
|
202
|
-
sql = `
|
|
203
|
-
SELECT
|
|
204
|
-
s.source,
|
|
205
|
-
s.title,
|
|
206
|
-
s.content,
|
|
207
|
-
s.metadata,
|
|
208
|
-
e.distance
|
|
209
|
-
FROM embeddings e
|
|
210
|
-
JOIN search s ON e.doc_id = s.rowid
|
|
211
|
-
WHERE e.embedding MATCH ?
|
|
212
|
-
AND k = ?
|
|
213
|
-
AND e.source = ?
|
|
214
|
-
ORDER BY e.distance
|
|
215
|
-
LIMIT ?
|
|
216
|
-
`;
|
|
217
|
-
params.push(limit);
|
|
205
|
+
conditions.push("e.source = ?");
|
|
218
206
|
params.push(options.source);
|
|
219
|
-
params.push(limit);
|
|
220
|
-
} else {
|
|
221
|
-
sql = `
|
|
222
|
-
SELECT
|
|
223
|
-
s.source,
|
|
224
|
-
s.title,
|
|
225
|
-
s.content,
|
|
226
|
-
s.metadata,
|
|
227
|
-
e.distance
|
|
228
|
-
FROM embeddings e
|
|
229
|
-
JOIN search s ON e.doc_id = s.rowid
|
|
230
|
-
WHERE e.embedding MATCH ?
|
|
231
|
-
AND k = ?
|
|
232
|
-
ORDER BY e.distance
|
|
233
|
-
LIMIT ?
|
|
234
|
-
`;
|
|
235
|
-
params.push(limit);
|
|
236
|
-
params.push(limit);
|
|
237
207
|
}
|
|
238
208
|
|
|
239
|
-
const stmt = db.prepare(sql);
|
|
240
|
-
const results = stmt.all(...params) as SemanticResult[];
|
|
241
|
-
|
|
242
|
-
// Post-filter by project if specified
|
|
243
|
-
// KNN WHERE clause doesn't support json_extract on joined metadata,
|
|
244
|
-
// so we filter after the query returns
|
|
245
209
|
if (options.project) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (!field) return false;
|
|
249
|
-
|
|
250
|
-
try {
|
|
251
|
-
const metadata = JSON.parse(result.metadata);
|
|
252
|
-
return metadata[field] === options.project;
|
|
253
|
-
} catch {
|
|
254
|
-
// Skip results with malformed metadata
|
|
255
|
-
return false;
|
|
256
|
-
}
|
|
257
|
-
});
|
|
210
|
+
conditions.push("e.topic = ?");
|
|
211
|
+
params.push(options.project);
|
|
258
212
|
}
|
|
259
213
|
|
|
214
|
+
sql = `
|
|
215
|
+
SELECT
|
|
216
|
+
s.source,
|
|
217
|
+
s.title,
|
|
218
|
+
s.content,
|
|
219
|
+
s.metadata,
|
|
220
|
+
e.distance
|
|
221
|
+
FROM embeddings e
|
|
222
|
+
JOIN search s ON e.doc_id = s.rowid
|
|
223
|
+
WHERE ${conditions.join("\n AND ")}
|
|
224
|
+
ORDER BY e.distance
|
|
225
|
+
LIMIT ?
|
|
226
|
+
`;
|
|
227
|
+
params.push(limit);
|
|
228
|
+
|
|
229
|
+
const stmt = db.prepare(sql);
|
|
230
|
+
const results = stmt.all(...params) as SemanticResult[];
|
|
231
|
+
|
|
260
232
|
return results;
|
|
261
233
|
} finally {
|
|
262
234
|
db.close();
|