context-vault 3.18.0 → 3.19.0
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/bin/cli.js +157 -0
- package/dist/register-tools.d.ts.map +1 -1
- package/dist/register-tools.js +0 -2
- package/dist/register-tools.js.map +1 -1
- package/dist/server.js +78 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/recall.d.ts +1 -1
- package/dist/tools/recall.d.ts.map +1 -1
- package/dist/tools/recall.js +50 -100
- package/dist/tools/recall.js.map +1 -1
- package/node_modules/@context-vault/core/dist/assemble.d.ts +22 -0
- package/node_modules/@context-vault/core/dist/assemble.d.ts.map +1 -0
- package/node_modules/@context-vault/core/dist/assemble.js +143 -0
- package/node_modules/@context-vault/core/dist/assemble.js.map +1 -0
- package/node_modules/@context-vault/core/dist/capture.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/capture.js +10 -5
- package/node_modules/@context-vault/core/dist/capture.js.map +1 -1
- package/node_modules/@context-vault/core/dist/consolidation.d.ts +40 -0
- package/node_modules/@context-vault/core/dist/consolidation.d.ts.map +1 -0
- package/node_modules/@context-vault/core/dist/consolidation.js +229 -0
- package/node_modules/@context-vault/core/dist/consolidation.js.map +1 -0
- package/node_modules/@context-vault/core/dist/db.d.ts +25 -1
- package/node_modules/@context-vault/core/dist/db.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/db.js +92 -4
- package/node_modules/@context-vault/core/dist/db.js.map +1 -1
- package/node_modules/@context-vault/core/dist/frontmatter.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/frontmatter.js +26 -3
- package/node_modules/@context-vault/core/dist/frontmatter.js.map +1 -1
- package/node_modules/@context-vault/core/dist/index.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/index.js +225 -184
- package/node_modules/@context-vault/core/dist/index.js.map +1 -1
- package/node_modules/@context-vault/core/dist/main.d.ts +2 -0
- package/node_modules/@context-vault/core/dist/main.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/main.js +2 -0
- package/node_modules/@context-vault/core/dist/main.js.map +1 -1
- package/node_modules/@context-vault/core/dist/search.d.ts +5 -0
- package/node_modules/@context-vault/core/dist/search.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/search.js +97 -5
- package/node_modules/@context-vault/core/dist/search.js.map +1 -1
- package/node_modules/@context-vault/core/dist/summarize.d.ts +5 -0
- package/node_modules/@context-vault/core/dist/summarize.d.ts.map +1 -0
- package/node_modules/@context-vault/core/dist/summarize.js +146 -0
- package/node_modules/@context-vault/core/dist/summarize.js.map +1 -0
- package/node_modules/@context-vault/core/dist/types.d.ts +2 -0
- package/node_modules/@context-vault/core/dist/types.d.ts.map +1 -1
- package/node_modules/@context-vault/core/package.json +5 -1
- package/node_modules/@context-vault/core/src/assemble.ts +187 -0
- package/node_modules/@context-vault/core/src/capture.ts +10 -5
- package/node_modules/@context-vault/core/src/consolidation.ts +356 -0
- package/node_modules/@context-vault/core/src/db.ts +95 -4
- package/node_modules/@context-vault/core/src/frontmatter.ts +25 -4
- package/node_modules/@context-vault/core/src/index.ts +127 -88
- package/node_modules/@context-vault/core/src/main.ts +4 -0
- package/node_modules/@context-vault/core/src/search.ts +102 -5
- package/node_modules/@context-vault/core/src/summarize.ts +157 -0
- package/node_modules/@context-vault/core/src/types.ts +2 -0
- package/package.json +2 -2
- package/scripts/validate-epipe-shutdown.mjs +183 -0
- package/scripts/validate-sqlite-busy-retry.mjs +243 -0
- package/src/register-tools.ts +0 -2
- package/src/server.ts +76 -1
- package/src/tools/recall.ts +51 -110
package/src/tools/recall.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { ok } from '../helpers.js';
|
|
3
|
-
import {
|
|
3
|
+
import { hybridSearch } from '@context-vault/core/search';
|
|
4
4
|
import { getAutoMemory, findAutoMemoryOverlaps } from '../auto-memory.js';
|
|
5
5
|
import { getRemoteClient, getTeamId, getPublicVaults } from '../remote.js';
|
|
6
6
|
import type { LocalCtx, SharedCtx, ToolResult } from '../types.js';
|
|
7
|
+
import type { SearchOptions } from '@context-vault/core/types';
|
|
7
8
|
|
|
8
|
-
const SEMANTIC_SIMILARITY_THRESHOLD = 0.6;
|
|
9
9
|
const CO_RETRIEVAL_WEIGHT_CAP = 50;
|
|
10
10
|
|
|
11
11
|
const STOPWORDS = new Set([
|
|
@@ -31,14 +31,14 @@ const sessionSurfaced = new Map<string, Set<string>>();
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Extract keywords from a signal string.
|
|
34
|
-
* Split on whitespace, filter stopwords and words under
|
|
34
|
+
* Split on whitespace, filter stopwords and words under 2 chars, keep top 10.
|
|
35
35
|
*/
|
|
36
36
|
export function extractKeywords(signal: string): string[] {
|
|
37
37
|
const words = signal
|
|
38
38
|
.toLowerCase()
|
|
39
39
|
.replace(/[^a-z0-9\s_-]/g, ' ')
|
|
40
40
|
.split(/\s+/)
|
|
41
|
-
.filter((w) => w.length >=
|
|
41
|
+
.filter((w) => w.length >= 2 && !STOPWORDS.has(w));
|
|
42
42
|
|
|
43
43
|
const seen = new Set<string>();
|
|
44
44
|
const unique: string[] = [];
|
|
@@ -100,30 +100,48 @@ export async function handler(
|
|
|
100
100
|
return result;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
// Build
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const bucketClause = bucket ? ' AND tags LIKE ?' : '';
|
|
112
|
-
if (bucket) params.push(`%"bucket:${bucket}"%`);
|
|
103
|
+
// Build search query from signal, enriched by signal_type
|
|
104
|
+
let searchQuery = signal || '';
|
|
105
|
+
const searchOpts: SearchOptions = {
|
|
106
|
+
excludeEvents: true,
|
|
107
|
+
limit: limit * 3, // over-fetch to allow for session dedup + bucket filtering
|
|
108
|
+
};
|
|
113
109
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
110
|
+
// Signal-type aware search options
|
|
111
|
+
switch (signal_type) {
|
|
112
|
+
case 'error':
|
|
113
|
+
// Errors should boost recent entries
|
|
114
|
+
searchOpts.decayDays = 7;
|
|
115
|
+
break;
|
|
116
|
+
case 'file':
|
|
117
|
+
// Extract path components and extension as additional search terms
|
|
118
|
+
searchQuery = signal
|
|
119
|
+
.replace(/[/\\]/g, ' ')
|
|
120
|
+
.replace(/\./g, ' ')
|
|
121
|
+
.trim();
|
|
122
|
+
break;
|
|
123
|
+
case 'task':
|
|
124
|
+
// Tasks benefit from wider search
|
|
125
|
+
searchOpts.limit = Math.max(searchOpts.limit!, limit * 5);
|
|
126
|
+
break;
|
|
127
|
+
// 'prompt': standard hybrid search, no modifications
|
|
128
|
+
}
|
|
121
129
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
130
|
+
// Run hybrid search (FTS + vector + tag lanes with RRF fusion)
|
|
131
|
+
let searchResults = await hybridSearch(ctx, searchQuery, searchOpts);
|
|
132
|
+
|
|
133
|
+
// Bucket-aware post-filtering
|
|
134
|
+
if (bucket) {
|
|
135
|
+
const bucketTag = `bucket:${bucket}`;
|
|
136
|
+
searchResults = searchResults.filter((r) => {
|
|
137
|
+
if (!r.tags) return false;
|
|
138
|
+
try {
|
|
139
|
+
const tags: string[] = typeof r.tags === 'string' ? JSON.parse(r.tags) : r.tags;
|
|
140
|
+
return tags.some((t) => t === bucketTag);
|
|
141
|
+
} catch {
|
|
142
|
+
return String(r.tags).includes(bucketTag);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
127
145
|
}
|
|
128
146
|
|
|
129
147
|
// Session dedup
|
|
@@ -142,7 +160,7 @@ export async function handler(
|
|
|
142
160
|
tags: string[];
|
|
143
161
|
}> = [];
|
|
144
162
|
|
|
145
|
-
for (const row of
|
|
163
|
+
for (const row of searchResults) {
|
|
146
164
|
if (hints.length >= limit) break;
|
|
147
165
|
|
|
148
166
|
// Dedup check
|
|
@@ -151,21 +169,16 @@ export async function handler(
|
|
|
151
169
|
continue;
|
|
152
170
|
}
|
|
153
171
|
|
|
154
|
-
const entryTags: string[] = row.tags
|
|
172
|
+
const entryTags: string[] = row.tags
|
|
173
|
+
? (typeof row.tags === 'string' ? JSON.parse(row.tags) : row.tags)
|
|
174
|
+
: [];
|
|
155
175
|
|
|
156
|
-
|
|
157
|
-
let matchCount = 0;
|
|
158
|
-
const titleLower = (row.title || '').toLowerCase();
|
|
159
|
-
const tagsLower = (row.tags || '').toLowerCase();
|
|
160
|
-
for (const kw of keywords) {
|
|
161
|
-
if (titleLower.includes(kw) || tagsLower.includes(kw)) matchCount++;
|
|
162
|
-
}
|
|
163
|
-
const relevance: 'high' | 'medium' = matchCount >= 2 ? 'high' : 'medium';
|
|
176
|
+
const relevance: 'high' | 'medium' = row.score >= 0.02 ? 'high' : 'medium';
|
|
164
177
|
|
|
165
178
|
hints.push({
|
|
166
179
|
id: row.id,
|
|
167
180
|
title: row.title || '(untitled)',
|
|
168
|
-
summary: row.
|
|
181
|
+
summary: row.body ? row.body.slice(0, 100) : '',
|
|
169
182
|
relevance,
|
|
170
183
|
kind: row.kind || 'knowledge',
|
|
171
184
|
tags: entryTags,
|
|
@@ -261,79 +274,7 @@ export async function handler(
|
|
|
261
274
|
}
|
|
262
275
|
}
|
|
263
276
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
// Semantic fallback: when fast-path returns 0 results and signal is not file-based
|
|
267
|
-
if (hints.length === 0 && signal_type !== 'file' && isEmbedAvailable()) {
|
|
268
|
-
try {
|
|
269
|
-
const vecCount = (
|
|
270
|
-
ctx.db.prepare('SELECT COUNT(*) as c FROM vault_vec').get() as { c: number }
|
|
271
|
-
).c;
|
|
272
|
-
|
|
273
|
-
if (vecCount > 0) {
|
|
274
|
-
const queryVec = await ctx.embed(signal);
|
|
275
|
-
if (queryVec) {
|
|
276
|
-
const vecRows = ctx.db
|
|
277
|
-
.prepare(
|
|
278
|
-
'SELECT v.rowid, v.distance FROM vault_vec v WHERE embedding MATCH ? ORDER BY distance LIMIT 5'
|
|
279
|
-
)
|
|
280
|
-
.all(queryVec) as { rowid: number; distance: number }[];
|
|
281
|
-
|
|
282
|
-
if (vecRows.length) {
|
|
283
|
-
const rowids = vecRows.map((vr) => vr.rowid);
|
|
284
|
-
const placeholders = rowids.map(() => '?').join(',');
|
|
285
|
-
|
|
286
|
-
let bucketFilter = '';
|
|
287
|
-
const hydrateParams: any[] = [...rowids];
|
|
288
|
-
if (bucket) {
|
|
289
|
-
bucketFilter = ' AND tags LIKE ?';
|
|
290
|
-
hydrateParams.push(`%"bucket:${bucket}"%`);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const hydrated = ctx.db
|
|
294
|
-
.prepare(
|
|
295
|
-
`SELECT rowid, id, title, substr(body, 1, 100) as summary, kind, tags FROM vault WHERE rowid IN (${placeholders}) AND indexed = 1 AND (expires_at IS NULL OR expires_at > datetime('now')) AND superseded_by IS NULL${bucketFilter}`
|
|
296
|
-
)
|
|
297
|
-
.all(...hydrateParams) as any[];
|
|
298
|
-
|
|
299
|
-
const byRowid = new Map<number, any>();
|
|
300
|
-
for (const row of hydrated) byRowid.set(row.rowid, row);
|
|
301
|
-
|
|
302
|
-
for (const vr of vecRows) {
|
|
303
|
-
if (hints.length >= limit) break;
|
|
304
|
-
const row = byRowid.get(vr.rowid);
|
|
305
|
-
if (!row) continue;
|
|
306
|
-
|
|
307
|
-
const similarity = Math.max(0, 1 - vr.distance / 2);
|
|
308
|
-
if (similarity < SEMANTIC_SIMILARITY_THRESHOLD) continue;
|
|
309
|
-
|
|
310
|
-
// Session dedup
|
|
311
|
-
if (sessionSet && !bypassDedup && sessionSet.has(row.id)) {
|
|
312
|
-
suppressed++;
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const entryTags: string[] = row.tags ? JSON.parse(row.tags) : [];
|
|
317
|
-
hints.push({
|
|
318
|
-
id: row.id,
|
|
319
|
-
title: row.title || '(untitled)',
|
|
320
|
-
summary: row.summary || '',
|
|
321
|
-
relevance: similarity >= 0.8 ? 'high' : 'medium',
|
|
322
|
-
kind: row.kind || 'knowledge',
|
|
323
|
-
tags: entryTags,
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
if (sessionSet) sessionSet.add(row.id);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if (hints.length > 0) method = 'semantic';
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
} catch {
|
|
334
|
-
// Semantic fallback is best-effort; fast path already ran
|
|
335
|
-
}
|
|
336
|
-
}
|
|
277
|
+
const method: 'hybrid' | 'none' = hints.length > 0 ? 'hybrid' : 'none';
|
|
337
278
|
|
|
338
279
|
const latency = Date.now() - start;
|
|
339
280
|
|