@psiclawops/hypermem 0.9.6 → 0.9.9
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/CHANGELOG.md +23 -0
- package/INSTALL.md +29 -9
- package/README.md +5 -1
- package/assets/default-config.json +20 -5
- package/assets/runtime-validation-fixture.json +123 -0
- package/bin/hypermem-cleanup.mjs +334 -0
- package/bin/hypermem-doctor.mjs +71 -0
- package/bin/hypermem-validate-runtime.mjs +282 -0
- package/dist/compositor.d.ts +43 -5
- package/dist/compositor.d.ts.map +1 -1
- package/dist/compositor.js +802 -30
- package/dist/entity-bridge-backfill.d.ts +66 -0
- package/dist/entity-bridge-backfill.d.ts.map +1 -0
- package/dist/entity-bridge-backfill.js +145 -0
- package/dist/entity-bridge-store.d.ts +164 -0
- package/dist/entity-bridge-store.d.ts.map +1 -0
- package/dist/entity-bridge-store.js +488 -0
- package/dist/entity-extractor.d.ts +124 -0
- package/dist/entity-extractor.d.ts.map +1 -0
- package/dist/entity-extractor.js +382 -0
- package/dist/entity-ppr.d.ts +55 -0
- package/dist/entity-ppr.d.ts.map +1 -0
- package/dist/entity-ppr.js +180 -0
- package/dist/hybrid-retrieval.d.ts +27 -0
- package/dist/hybrid-retrieval.d.ts.map +1 -1
- package/dist/hybrid-retrieval.js +26 -1
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -13
- package/dist/message-store.d.ts +36 -0
- package/dist/message-store.d.ts.map +1 -1
- package/dist/message-store.js +155 -1
- package/dist/open-domain.d.ts +13 -4
- package/dist/open-domain.d.ts.map +1 -1
- package/dist/open-domain.js +222 -20
- package/dist/profiles.js +13 -13
- package/dist/question-shape.d.ts +73 -0
- package/dist/question-shape.d.ts.map +1 -0
- package/dist/question-shape.js +230 -0
- package/dist/schema.d.ts +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +92 -1
- package/dist/topic-detector.d.ts.map +1 -1
- package/dist/topic-detector.js +22 -9
- package/dist/types.d.ts +176 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-store.d.ts +6 -0
- package/dist/vector-store.d.ts.map +1 -1
- package/dist/vector-store.js +3 -0
- package/docs/DIAGNOSTICS.md +47 -0
- package/docs/INTEGRATION_VALIDATION.md +24 -4
- package/docs/TUNING.md +21 -21
- package/memory-plugin/dist/index.d.ts +3 -3
- package/memory-plugin/dist/index.js +4 -2
- package/memory-plugin/openclaw.plugin.json +5 -0
- package/memory-plugin/package.json +10 -6
- package/package.json +22 -5
- package/plugin/dist/index.d.ts +3 -3
- package/plugin/dist/index.d.ts.map +1 -1
- package/plugin/dist/index.js +115 -13
- package/plugin/dist/index.js.map +1 -1
- package/plugin/package.json +10 -6
- package/scripts/install-runtime.mjs +4 -1
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* entity-extractor.ts — Entity and facet tagger
|
|
3
|
+
*
|
|
4
|
+
* Sprint A: compose-time annotation only.
|
|
5
|
+
* Sprint B: also used at ingest time. Adds shared key normalization
|
|
6
|
+
* (`normalizeEntityKey`, `normalizeFacetKey`) and an ingest-friendly
|
|
7
|
+
* `extractEntityFacetMentions(text)` returning cheap (start,end) offsets
|
|
8
|
+
* suitable for storing in `message_entity_mentions` / `message_facet_mentions`.
|
|
9
|
+
*
|
|
10
|
+
* Exported symbols:
|
|
11
|
+
* extractEntitiesFromText(text, knownEntities?) → ExtractedTextEntities
|
|
12
|
+
* annotateRecallGroups(...) → AnnotatedGroup[]
|
|
13
|
+
* formatStructuredHandoffBlock(...) → structured block
|
|
14
|
+
* buildStructuredHandoffInstruction(...) → string
|
|
15
|
+
* normalizeEntityKey(token) → string (Sprint B)
|
|
16
|
+
* normalizeFacetKey(token) → string (Sprint B)
|
|
17
|
+
* extractEntityFacetMentions(text) → EntityFacetMentions (Sprint B)
|
|
18
|
+
*/
|
|
19
|
+
import { QUESTION_SHAPE_FACETS, extractQueryFacetTerms, } from './question-shape.js';
|
|
20
|
+
// ── Internal helpers ──────────────────────────────────────────────────────
|
|
21
|
+
/** TitleCase word pattern for content scanning */
|
|
22
|
+
const TITLE_CASE_CONTENT_WORD = /\b[A-Z][a-z][a-zA-Z]*\b/g;
|
|
23
|
+
/** Quoted string pattern */
|
|
24
|
+
const QUOTED_STRING_CONTENT = /["']([^"']{2,30})["']/g;
|
|
25
|
+
/** ALL-CAPS abbreviation */
|
|
26
|
+
const ALLCAPS_ABBREV_CONTENT = /\b[A-Z]{2,6}\b/g;
|
|
27
|
+
const CONTENT_STOP_WORDS = new Set([
|
|
28
|
+
'the', 'a', 'an', 'in', 'on', 'at', 'to', 'for', 'of', 'and', 'or', 'but',
|
|
29
|
+
'by', 'is', 'it', 'if', 'so', 'do', 'be', 'my', 'we', 'he', 'she', 'they',
|
|
30
|
+
'you', 'me', 'us', 'his', 'her', 'its', 'our', 'your', 'who', 'what', 'how',
|
|
31
|
+
'when', 'where', 'which', 'why', 'would', 'could', 'should', 'did', 'does',
|
|
32
|
+
'was', 'were', 'has', 'have', 'had', 'will', 'can', 'may', 'might', 'shall',
|
|
33
|
+
'just', 'also', 'both', 'each', 'with', 'from', 'that', 'this', 'these',
|
|
34
|
+
'those', 'any', 'all', 'not', 'now', 'well', 'too', 'very', 'more', 'most',
|
|
35
|
+
'some', 'same', 'last', 'next', 'new', 'old', 'then', 'than', 'into', 'upon',
|
|
36
|
+
// Role labels that appear in recall blocks
|
|
37
|
+
'user', 'assistant', 'raw', 'transcript', 'group',
|
|
38
|
+
// Common discourse words
|
|
39
|
+
'yes', 'yeah', 'okay', 'ok', 'sure', 'right', 'true', 'false',
|
|
40
|
+
// Date words
|
|
41
|
+
'january', 'february', 'march', 'april', 'june', 'july', 'august',
|
|
42
|
+
'september', 'october', 'november', 'december',
|
|
43
|
+
]);
|
|
44
|
+
/**
|
|
45
|
+
* Extract entity and facet tokens from a block of text content.
|
|
46
|
+
* When `knownEntities` is provided, the scan is biased toward those tokens
|
|
47
|
+
* (useful for narrowing to query-relevant entities during structured handoff).
|
|
48
|
+
*/
|
|
49
|
+
export function extractEntitiesFromText(text, knownEntities) {
|
|
50
|
+
const entities = new Set();
|
|
51
|
+
const lower = text.toLowerCase();
|
|
52
|
+
// If caller provides a known entity list, check those first (fast path)
|
|
53
|
+
if (knownEntities && knownEntities.length > 0) {
|
|
54
|
+
for (const e of knownEntities) {
|
|
55
|
+
if (lower.includes(e.toLowerCase())) {
|
|
56
|
+
entities.add(e.toLowerCase());
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Always scan for TitleCase entities (catches entities not in knownEntities)
|
|
61
|
+
for (const m of text.matchAll(TITLE_CASE_CONTENT_WORD)) {
|
|
62
|
+
const word = m[0];
|
|
63
|
+
const wLower = word.toLowerCase();
|
|
64
|
+
if (!CONTENT_STOP_WORDS.has(wLower)) {
|
|
65
|
+
entities.add(wLower);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Quoted strings
|
|
69
|
+
for (const m of text.matchAll(QUOTED_STRING_CONTENT)) {
|
|
70
|
+
const val = m[1].trim().toLowerCase();
|
|
71
|
+
if (val.length >= 2 && !CONTENT_STOP_WORDS.has(val)) {
|
|
72
|
+
entities.add(val);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// ALL-CAPS abbreviations
|
|
76
|
+
for (const m of text.matchAll(ALLCAPS_ABBREV_CONTENT)) {
|
|
77
|
+
const abbrev = m[0].toLowerCase();
|
|
78
|
+
if (abbrev.length >= 2 && !CONTENT_STOP_WORDS.has(abbrev)) {
|
|
79
|
+
entities.add(abbrev);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Facets
|
|
83
|
+
const facets = new Set();
|
|
84
|
+
const facetTerms = [];
|
|
85
|
+
for (const facet of QUESTION_SHAPE_FACETS) {
|
|
86
|
+
for (const term of facet.terms) {
|
|
87
|
+
if (lower.includes(term)) {
|
|
88
|
+
facets.add(facet.name);
|
|
89
|
+
facetTerms.push(term);
|
|
90
|
+
break; // one match per facet group is enough
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
entities: [...entities],
|
|
96
|
+
facets: [...facets],
|
|
97
|
+
facetTerms: [...new Set(facetTerms)],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// ── Group annotator ───────────────────────────────────────────────────────
|
|
101
|
+
/**
|
|
102
|
+
* Parse raw recall content (already grouped by conversation_id) into annotated groups.
|
|
103
|
+
*
|
|
104
|
+
* Input is the `recall.content` string from `buildQueryMessageRecall()`,
|
|
105
|
+
* which uses `### Raw transcript group {id}` headers.
|
|
106
|
+
*
|
|
107
|
+
* For each group, annotates which query entities and facets appear in the
|
|
108
|
+
* group's content lines. This is the core of the Sprint A structured handoff.
|
|
109
|
+
*/
|
|
110
|
+
export function annotateRecallGroups(recallContent, queryEntities, queryFacets) {
|
|
111
|
+
const groups = [];
|
|
112
|
+
const queryFacetTerms = extractQueryFacetTerms(queryFacets.join(' '));
|
|
113
|
+
// Build a set of raw facet terms for matching within group content
|
|
114
|
+
const facetTermsByGroup = new Map();
|
|
115
|
+
for (const facetName of queryFacets) {
|
|
116
|
+
const facet = QUESTION_SHAPE_FACETS.find(f => f.name === facetName);
|
|
117
|
+
if (facet) {
|
|
118
|
+
facetTermsByGroup.set(facetName, facet.terms);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Split content by group headers
|
|
122
|
+
const groupHeaderPattern = /^### Raw transcript group (\S+)/m;
|
|
123
|
+
const parts = recallContent.split(/^(?=### Raw transcript group \S+)/m);
|
|
124
|
+
for (const part of parts) {
|
|
125
|
+
if (!part.trim())
|
|
126
|
+
continue;
|
|
127
|
+
const headerMatch = part.match(groupHeaderPattern);
|
|
128
|
+
if (!headerMatch)
|
|
129
|
+
continue;
|
|
130
|
+
const groupId = headerMatch[1];
|
|
131
|
+
const lines = part.split('\n');
|
|
132
|
+
const contentLines = lines.slice(1); // skip header line
|
|
133
|
+
// Flatten group text for entity/facet matching
|
|
134
|
+
const groupText = contentLines.join(' ');
|
|
135
|
+
const groupLower = groupText.toLowerCase();
|
|
136
|
+
// Which query entities appear in this group?
|
|
137
|
+
const matchedEntities = queryEntities.filter(e => groupLower.includes(e.toLowerCase()));
|
|
138
|
+
// Which query facet groups appear in this group?
|
|
139
|
+
const matchedFacets = [];
|
|
140
|
+
const matchedFacetTerms = [];
|
|
141
|
+
for (const [facetName, terms] of facetTermsByGroup) {
|
|
142
|
+
const matched = terms.filter(t => groupLower.includes(t));
|
|
143
|
+
if (matched.length > 0) {
|
|
144
|
+
matchedFacets.push(facetName);
|
|
145
|
+
matchedFacetTerms.push(...matched);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
groups.push({
|
|
149
|
+
groupId,
|
|
150
|
+
lines: contentLines,
|
|
151
|
+
matchedEntities,
|
|
152
|
+
matchedFacets,
|
|
153
|
+
matchedFacetTerms: [...new Set(matchedFacetTerms)],
|
|
154
|
+
isRelevant: matchedEntities.length > 0 || matchedFacets.length > 0,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return groups;
|
|
158
|
+
}
|
|
159
|
+
// ── Structured handoff formatter ──────────────────────────────────────────
|
|
160
|
+
/**
|
|
161
|
+
* Format annotated groups into structured evidence blocks for multi-hop handoff.
|
|
162
|
+
*
|
|
163
|
+
* Each group gets a header that names which query entities/facets it contains,
|
|
164
|
+
* so the reader can quickly identify which groups are evidence for each hop.
|
|
165
|
+
*
|
|
166
|
+
* Token cost is minimal relative to the raw content: only the header changes.
|
|
167
|
+
* No content is dropped; existing budget accounting from buildQueryMessageRecall
|
|
168
|
+
* applies before this formatter runs.
|
|
169
|
+
*/
|
|
170
|
+
export function formatStructuredHandoffBlock(groups, queryEntities, queryFacets) {
|
|
171
|
+
const lines = [];
|
|
172
|
+
let entityGroupCount = 0;
|
|
173
|
+
let facetGroupCount = 0;
|
|
174
|
+
for (const group of groups) {
|
|
175
|
+
const hasMeaningfulContent = group.lines.some(l => l.trim().startsWith('-'));
|
|
176
|
+
if (!hasMeaningfulContent)
|
|
177
|
+
continue;
|
|
178
|
+
// Build a compact annotation for the group header
|
|
179
|
+
const annotations = [];
|
|
180
|
+
if (group.matchedEntities.length > 0) {
|
|
181
|
+
annotations.push(`entities: ${group.matchedEntities.slice(0, 4).join(', ')}`);
|
|
182
|
+
entityGroupCount++;
|
|
183
|
+
}
|
|
184
|
+
if (group.matchedFacets.length > 0) {
|
|
185
|
+
annotations.push(`facets: ${group.matchedFacets.slice(0, 3).join(', ')}`);
|
|
186
|
+
facetGroupCount++;
|
|
187
|
+
}
|
|
188
|
+
// Emit header with annotation (or without if no match — still emit the group)
|
|
189
|
+
if (annotations.length > 0) {
|
|
190
|
+
lines.push(`### Evidence group ${group.groupId} [${annotations.join('; ')}]`);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
lines.push(`### Raw transcript group ${group.groupId}`);
|
|
194
|
+
}
|
|
195
|
+
// Emit content lines (unchanged from recall output)
|
|
196
|
+
for (const line of group.lines) {
|
|
197
|
+
if (line.trim())
|
|
198
|
+
lines.push(line);
|
|
199
|
+
}
|
|
200
|
+
lines.push('');
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
content: lines.join('\n').trimEnd(),
|
|
204
|
+
entityGroupCount,
|
|
205
|
+
facetGroupCount,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
// ── Sprint B: shared key normalization and ingest extraction ─────────────
|
|
209
|
+
/**
|
|
210
|
+
* Normalize an entity surface form into a canonical bridge key.
|
|
211
|
+
*
|
|
212
|
+
* Strategy: lowercase, collapse whitespace, strip leading/trailing punctuation,
|
|
213
|
+
* preserve internal alphanumerics + a small set of joiners (-, _, .).
|
|
214
|
+
* The result is the join key used by `memory_entities.entity_key`.
|
|
215
|
+
*/
|
|
216
|
+
export function normalizeEntityKey(token) {
|
|
217
|
+
if (!token)
|
|
218
|
+
return '';
|
|
219
|
+
const trimmed = String(token).trim().toLowerCase();
|
|
220
|
+
if (!trimmed)
|
|
221
|
+
return '';
|
|
222
|
+
// Collapse internal whitespace, strip leading/trailing punctuation.
|
|
223
|
+
const collapsed = trimmed.replace(/\s+/g, ' ');
|
|
224
|
+
return collapsed.replace(/^[^a-z0-9]+|[^a-z0-9]+$/g, '');
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Normalize a facet group name into a canonical bridge key.
|
|
228
|
+
* Facet keys are already lowercase identifiers in QUESTION_SHAPE_FACETS,
|
|
229
|
+
* but callers may pass raw terms. We snap raw terms to their facet group.
|
|
230
|
+
*/
|
|
231
|
+
export function normalizeFacetKey(token) {
|
|
232
|
+
if (!token)
|
|
233
|
+
return '';
|
|
234
|
+
const lower = String(token).trim().toLowerCase();
|
|
235
|
+
if (!lower)
|
|
236
|
+
return '';
|
|
237
|
+
// If the token is already a facet group name, return it.
|
|
238
|
+
for (const f of QUESTION_SHAPE_FACETS) {
|
|
239
|
+
if (f.name === lower)
|
|
240
|
+
return lower;
|
|
241
|
+
}
|
|
242
|
+
// Otherwise look it up against the term list.
|
|
243
|
+
for (const f of QUESTION_SHAPE_FACETS) {
|
|
244
|
+
if (f.terms.includes(lower))
|
|
245
|
+
return f.name;
|
|
246
|
+
}
|
|
247
|
+
return lower.replace(/^[^a-z0-9]+|[^a-z0-9]+$/g, '');
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Internal helper: yield a regex that matches the union of facet terms with
|
|
251
|
+
* word boundaries where possible. Cached at module level.
|
|
252
|
+
*/
|
|
253
|
+
let _facetTermPattern = null;
|
|
254
|
+
let _facetTermLookup = null;
|
|
255
|
+
function getFacetTermPattern() {
|
|
256
|
+
if (_facetTermPattern && _facetTermLookup) {
|
|
257
|
+
return { pattern: _facetTermPattern, lookup: _facetTermLookup };
|
|
258
|
+
}
|
|
259
|
+
const lookup = new Map();
|
|
260
|
+
const escaped = [];
|
|
261
|
+
for (const facet of QUESTION_SHAPE_FACETS) {
|
|
262
|
+
for (const term of facet.terms) {
|
|
263
|
+
// Last write wins for ambiguous terms; QUESTION_SHAPE_FACETS authors
|
|
264
|
+
// are responsible for keeping the lexicon disjoint enough.
|
|
265
|
+
lookup.set(term.toLowerCase(), facet.name);
|
|
266
|
+
escaped.push(term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Sort by length descending so multi-word terms beat single-word prefixes.
|
|
270
|
+
escaped.sort((a, b) => b.length - a.length);
|
|
271
|
+
_facetTermPattern = new RegExp(`\\b(?:${escaped.join('|')})\\b`, 'gi');
|
|
272
|
+
_facetTermLookup = lookup;
|
|
273
|
+
return { pattern: _facetTermPattern, lookup };
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Extract entity and facet mentions from a text block, with cheap (start,end)
|
|
277
|
+
* offsets, for ingest indexing into the entity/facet bridge tables.
|
|
278
|
+
*
|
|
279
|
+
* Designed to be cheap and deterministic; never calls a model, never reads
|
|
280
|
+
* a DB. Caller decides whether to write the resulting mentions.
|
|
281
|
+
*/
|
|
282
|
+
export function extractEntityFacetMentions(text) {
|
|
283
|
+
const entities = [];
|
|
284
|
+
const facets = [];
|
|
285
|
+
if (!text)
|
|
286
|
+
return { entities, facets };
|
|
287
|
+
const seenEntity = new Map();
|
|
288
|
+
// TitleCase entities
|
|
289
|
+
for (const m of text.matchAll(TITLE_CASE_CONTENT_WORD)) {
|
|
290
|
+
const surface = m[0];
|
|
291
|
+
const key = normalizeEntityKey(surface);
|
|
292
|
+
if (!key || CONTENT_STOP_WORDS.has(key))
|
|
293
|
+
continue;
|
|
294
|
+
if (seenEntity.has(key))
|
|
295
|
+
continue;
|
|
296
|
+
const start = m.index ?? text.indexOf(surface);
|
|
297
|
+
const end = start + surface.length;
|
|
298
|
+
const mention = { key, surface, start, end };
|
|
299
|
+
seenEntity.set(key, mention);
|
|
300
|
+
entities.push(mention);
|
|
301
|
+
}
|
|
302
|
+
// Quoted strings
|
|
303
|
+
for (const m of text.matchAll(QUOTED_STRING_CONTENT)) {
|
|
304
|
+
const inner = m[1];
|
|
305
|
+
const key = normalizeEntityKey(inner);
|
|
306
|
+
if (!key || key.length < 2 || CONTENT_STOP_WORDS.has(key))
|
|
307
|
+
continue;
|
|
308
|
+
if (seenEntity.has(key))
|
|
309
|
+
continue;
|
|
310
|
+
const matchStart = m.index ?? text.indexOf(m[0]);
|
|
311
|
+
const innerStart = matchStart + 1; // skip opening quote
|
|
312
|
+
const mention = {
|
|
313
|
+
key,
|
|
314
|
+
surface: inner,
|
|
315
|
+
start: innerStart,
|
|
316
|
+
end: innerStart + inner.length,
|
|
317
|
+
};
|
|
318
|
+
seenEntity.set(key, mention);
|
|
319
|
+
entities.push(mention);
|
|
320
|
+
}
|
|
321
|
+
// ALL-CAPS abbreviations
|
|
322
|
+
for (const m of text.matchAll(ALLCAPS_ABBREV_CONTENT)) {
|
|
323
|
+
const surface = m[0];
|
|
324
|
+
const key = normalizeEntityKey(surface);
|
|
325
|
+
if (!key || key.length < 2 || CONTENT_STOP_WORDS.has(key))
|
|
326
|
+
continue;
|
|
327
|
+
if (seenEntity.has(key))
|
|
328
|
+
continue;
|
|
329
|
+
const start = m.index ?? text.indexOf(surface);
|
|
330
|
+
const mention = {
|
|
331
|
+
key,
|
|
332
|
+
surface,
|
|
333
|
+
start,
|
|
334
|
+
end: start + surface.length,
|
|
335
|
+
};
|
|
336
|
+
seenEntity.set(key, mention);
|
|
337
|
+
entities.push(mention);
|
|
338
|
+
}
|
|
339
|
+
// Facet term scan
|
|
340
|
+
const { pattern, lookup } = getFacetTermPattern();
|
|
341
|
+
pattern.lastIndex = 0;
|
|
342
|
+
const seenFacetGroup = new Set();
|
|
343
|
+
let m;
|
|
344
|
+
while ((m = pattern.exec(text)) !== null) {
|
|
345
|
+
const term = m[0].toLowerCase();
|
|
346
|
+
const facetKey = lookup.get(term);
|
|
347
|
+
if (!facetKey)
|
|
348
|
+
continue;
|
|
349
|
+
// Keep the first occurrence per facet group; cheap and bounded.
|
|
350
|
+
if (seenFacetGroup.has(facetKey))
|
|
351
|
+
continue;
|
|
352
|
+
seenFacetGroup.add(facetKey);
|
|
353
|
+
facets.push({
|
|
354
|
+
key: facetKey,
|
|
355
|
+
term,
|
|
356
|
+
start: m.index,
|
|
357
|
+
end: m.index + term.length,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
return { entities, facets };
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Build the structured handoff instruction preamble.
|
|
364
|
+
* Replaces the current flat multi-hop instruction string when structured
|
|
365
|
+
* handoff is active.
|
|
366
|
+
*/
|
|
367
|
+
export function buildStructuredHandoffInstruction(entities, facets) {
|
|
368
|
+
const parts = [
|
|
369
|
+
'## Query-Matched Conversation Memory',
|
|
370
|
+
];
|
|
371
|
+
if (entities.length > 0 || facets.length > 0) {
|
|
372
|
+
const subjectParts = [];
|
|
373
|
+
if (entities.length > 0)
|
|
374
|
+
subjectParts.push(`entities: ${entities.slice(0, 4).join(', ')}`);
|
|
375
|
+
if (facets.length > 0)
|
|
376
|
+
subjectParts.push(`facets: ${facets.slice(0, 3).join(', ')}`);
|
|
377
|
+
parts.push(`Query subjects — ${subjectParts.join('; ')}.`);
|
|
378
|
+
}
|
|
379
|
+
parts.push('Evidence groups below are tagged with which query subjects appear in each group.', 'For multi-part questions, scan all groups and collect every relevant item before answering.', 'If the question asks what people share, have in common, bought, planned, pursued, or lost, scan all groups and include every matching item before summarizing.', 'Prefer the shortest complete list of supported items; do not add unsupported extras.', 'For names, places, events, purchases, deaths, goals, or activities, preserve each distinct transcript anchor you find instead of collapsing to a generic category.', 'Do not answer that no information is available when the groups contain supporting evidence.');
|
|
380
|
+
return parts.join('\n');
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=entity-extractor.js.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* entity-ppr.ts \u2014 Sprint B
|
|
3
|
+
*
|
|
4
|
+
* Sparse, in-memory Personalized PageRank over a small message/entity/facet
|
|
5
|
+
* adjacency snapshot from `EntityBridgeStore.buildGraphSnapshot()`.
|
|
6
|
+
*
|
|
7
|
+
* Caps:
|
|
8
|
+
* - Iteration cap (default 20).
|
|
9
|
+
* - Convergence tolerance (default 1e-6).
|
|
10
|
+
* - Hard message/edge caps come from the snapshot itself; PPR never grows it.
|
|
11
|
+
*
|
|
12
|
+
* Returns ranked message IDs and diagnostics. Never reads from the DB
|
|
13
|
+
* directly \u2014 callers pass an already-bounded snapshot.
|
|
14
|
+
*/
|
|
15
|
+
import type { BridgeGraphSnapshot } from './entity-bridge-store.js';
|
|
16
|
+
export interface PprOptions {
|
|
17
|
+
/** Restart probability (alpha). Default 0.15 \u2192 0.85 walk continuation. */
|
|
18
|
+
teleportProbability?: number;
|
|
19
|
+
/** Maximum power iterations. Default 20. */
|
|
20
|
+
maxIterations?: number;
|
|
21
|
+
/** L1 convergence tolerance over the score vector. Default 1e-6. */
|
|
22
|
+
convergenceTolerance?: number;
|
|
23
|
+
/** Optional cap on how many messages to return. Default: all ranked. */
|
|
24
|
+
topK?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface PprDiagnostics {
|
|
27
|
+
iterations: number;
|
|
28
|
+
converged: boolean;
|
|
29
|
+
/** Final L1 delta. */
|
|
30
|
+
delta: number;
|
|
31
|
+
/** Total messages scored. */
|
|
32
|
+
messageCount: number;
|
|
33
|
+
/** Number of seeds used. */
|
|
34
|
+
seedCount: number;
|
|
35
|
+
/** Whether seeds had no neighbors at all (dead start). */
|
|
36
|
+
emptyGraph: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface PprResult {
|
|
39
|
+
/** Ranked array of `{ messageId, score }` in descending order. */
|
|
40
|
+
ranked: Array<{
|
|
41
|
+
messageId: number;
|
|
42
|
+
score: number;
|
|
43
|
+
}>;
|
|
44
|
+
diagnostics: PprDiagnostics;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Run sparse personalized PageRank. The graph is bipartite-like:
|
|
48
|
+
* message <-> entity
|
|
49
|
+
* message <-> facet
|
|
50
|
+
*
|
|
51
|
+
* We treat each message/entity/facet as a node. Edge weights are uniform
|
|
52
|
+
* (1.0) within the snapshot \u2014 RRF/recency scoring is the caller's job.
|
|
53
|
+
*/
|
|
54
|
+
export declare function runPersonalizedPageRank(snapshot: BridgeGraphSnapshot, seedEntityKeys: string[], seedFacetKeys: string[], opts?: PprOptions): PprResult;
|
|
55
|
+
//# sourceMappingURL=entity-ppr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-ppr.d.ts","sourceRoot":"","sources":["../src/entity-ppr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,+EAA+E;IAC/E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,4CAA4C;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,MAAM,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,WAAW,EAAE,cAAc,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,mBAAmB,EAC7B,cAAc,EAAE,MAAM,EAAE,EACxB,aAAa,EAAE,MAAM,EAAE,EACvB,IAAI,CAAC,EAAE,UAAU,GAChB,SAAS,CA0JX"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* entity-ppr.ts \u2014 Sprint B
|
|
3
|
+
*
|
|
4
|
+
* Sparse, in-memory Personalized PageRank over a small message/entity/facet
|
|
5
|
+
* adjacency snapshot from `EntityBridgeStore.buildGraphSnapshot()`.
|
|
6
|
+
*
|
|
7
|
+
* Caps:
|
|
8
|
+
* - Iteration cap (default 20).
|
|
9
|
+
* - Convergence tolerance (default 1e-6).
|
|
10
|
+
* - Hard message/edge caps come from the snapshot itself; PPR never grows it.
|
|
11
|
+
*
|
|
12
|
+
* Returns ranked message IDs and diagnostics. Never reads from the DB
|
|
13
|
+
* directly \u2014 callers pass an already-bounded snapshot.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Run sparse personalized PageRank. The graph is bipartite-like:
|
|
17
|
+
* message <-> entity
|
|
18
|
+
* message <-> facet
|
|
19
|
+
*
|
|
20
|
+
* We treat each message/entity/facet as a node. Edge weights are uniform
|
|
21
|
+
* (1.0) within the snapshot \u2014 RRF/recency scoring is the caller's job.
|
|
22
|
+
*/
|
|
23
|
+
export function runPersonalizedPageRank(snapshot, seedEntityKeys, seedFacetKeys, opts) {
|
|
24
|
+
const alpha = clamp(opts?.teleportProbability ?? 0.15, 1e-3, 0.99);
|
|
25
|
+
const maxIters = Math.max(1, Math.min(200, opts?.maxIterations ?? 20));
|
|
26
|
+
const tol = Math.max(1e-12, opts?.convergenceTolerance ?? 1e-6);
|
|
27
|
+
// Build the union of node ids. We use string ids: 'm:<id>', 'e:<key>', 'f:<key>'.
|
|
28
|
+
const nodeIds = [];
|
|
29
|
+
const nodeIndex = new Map();
|
|
30
|
+
const adj = [];
|
|
31
|
+
function ensureNode(id) {
|
|
32
|
+
let idx = nodeIndex.get(id);
|
|
33
|
+
if (idx == null) {
|
|
34
|
+
idx = nodeIds.length;
|
|
35
|
+
nodeIds.push(id);
|
|
36
|
+
nodeIndex.set(id, idx);
|
|
37
|
+
adj.push([]);
|
|
38
|
+
}
|
|
39
|
+
return idx;
|
|
40
|
+
}
|
|
41
|
+
// Add edges: entity <-> message
|
|
42
|
+
for (const [key, msgs] of snapshot.entityMessages) {
|
|
43
|
+
const eIdx = ensureNode(`e:${key}`);
|
|
44
|
+
for (const mid of msgs) {
|
|
45
|
+
const mIdx = ensureNode(`m:${mid}`);
|
|
46
|
+
adj[eIdx].push(mIdx);
|
|
47
|
+
adj[mIdx].push(eIdx);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// facet <-> message (from seed expansion)
|
|
51
|
+
for (const [key, msgs] of snapshot.facetMessages) {
|
|
52
|
+
const fIdx = ensureNode(`f:${key}`);
|
|
53
|
+
for (const mid of msgs) {
|
|
54
|
+
const mIdx = ensureNode(`m:${mid}`);
|
|
55
|
+
adj[fIdx].push(mIdx);
|
|
56
|
+
adj[mIdx].push(fIdx);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Add second-hop adjacencies derived from messageEntities / messageFacets.
|
|
60
|
+
for (const [mid, ents] of snapshot.messageEntities) {
|
|
61
|
+
const mIdx = ensureNode(`m:${mid}`);
|
|
62
|
+
for (const ek of ents) {
|
|
63
|
+
const eIdx = ensureNode(`e:${ek}`);
|
|
64
|
+
adj[eIdx].push(mIdx);
|
|
65
|
+
adj[mIdx].push(eIdx);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const [mid, facs] of snapshot.messageFacets) {
|
|
69
|
+
const mIdx = ensureNode(`m:${mid}`);
|
|
70
|
+
for (const fk of facs) {
|
|
71
|
+
const fIdx = ensureNode(`f:${fk}`);
|
|
72
|
+
adj[fIdx].push(mIdx);
|
|
73
|
+
adj[mIdx].push(fIdx);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Build seed teleport vector.
|
|
77
|
+
const seedVec = new Float64Array(nodeIds.length);
|
|
78
|
+
let seedMass = 0;
|
|
79
|
+
for (const k of seedEntityKeys) {
|
|
80
|
+
const idx = nodeIndex.get(`e:${k}`);
|
|
81
|
+
if (idx != null) {
|
|
82
|
+
seedVec[idx] += 1;
|
|
83
|
+
seedMass += 1;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const k of seedFacetKeys) {
|
|
87
|
+
const idx = nodeIndex.get(`f:${k}`);
|
|
88
|
+
if (idx != null) {
|
|
89
|
+
seedVec[idx] += 1;
|
|
90
|
+
seedMass += 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (seedMass === 0 || nodeIds.length === 0) {
|
|
94
|
+
return {
|
|
95
|
+
ranked: [],
|
|
96
|
+
diagnostics: {
|
|
97
|
+
iterations: 0,
|
|
98
|
+
converged: true,
|
|
99
|
+
delta: 0,
|
|
100
|
+
messageCount: 0,
|
|
101
|
+
seedCount: seedEntityKeys.length + seedFacetKeys.length,
|
|
102
|
+
emptyGraph: true,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
for (let i = 0; i < seedVec.length; i++)
|
|
107
|
+
seedVec[i] /= seedMass;
|
|
108
|
+
// Power iteration: r_{t+1} = alpha * seedVec + (1 - alpha) * Wt * r_t
|
|
109
|
+
// where Wt is the column-stochastic transpose of the adjacency.
|
|
110
|
+
// For undirected adjacency we approximate degrees from neighbor counts.
|
|
111
|
+
const degrees = adj.map(n => n.length);
|
|
112
|
+
let r = new Float64Array(seedVec); // start at the seed distribution
|
|
113
|
+
let next = new Float64Array(nodeIds.length);
|
|
114
|
+
let iterations = 0;
|
|
115
|
+
let delta = Infinity;
|
|
116
|
+
let converged = false;
|
|
117
|
+
for (; iterations < maxIters; iterations++) {
|
|
118
|
+
next.fill(0);
|
|
119
|
+
for (let i = 0; i < nodeIds.length; i++) {
|
|
120
|
+
const ri = r[i];
|
|
121
|
+
if (ri === 0)
|
|
122
|
+
continue;
|
|
123
|
+
const neighbors = adj[i];
|
|
124
|
+
const deg = degrees[i];
|
|
125
|
+
if (deg === 0) {
|
|
126
|
+
// Dangling: contribute back to the seed distribution.
|
|
127
|
+
for (let s = 0; s < nodeIds.length; s++)
|
|
128
|
+
next[s] += ri * seedVec[s];
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const share = ri / deg;
|
|
132
|
+
for (const j of neighbors)
|
|
133
|
+
next[j] += share;
|
|
134
|
+
}
|
|
135
|
+
// Apply teleport.
|
|
136
|
+
delta = 0;
|
|
137
|
+
for (let i = 0; i < nodeIds.length; i++) {
|
|
138
|
+
const v = alpha * seedVec[i] + (1 - alpha) * next[i];
|
|
139
|
+
delta += Math.abs(v - r[i]);
|
|
140
|
+
next[i] = v;
|
|
141
|
+
}
|
|
142
|
+
// Swap r and next.
|
|
143
|
+
const tmp = r;
|
|
144
|
+
r = next;
|
|
145
|
+
next = tmp;
|
|
146
|
+
if (delta < tol) {
|
|
147
|
+
converged = true;
|
|
148
|
+
iterations++;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Collect message scores.
|
|
153
|
+
const ranked = [];
|
|
154
|
+
for (let i = 0; i < nodeIds.length; i++) {
|
|
155
|
+
const id = nodeIds[i];
|
|
156
|
+
if (id.charCodeAt(0) === 109 /* 'm' */ && id.charCodeAt(1) === 58 /* ':' */) {
|
|
157
|
+
const mid = Number(id.slice(2));
|
|
158
|
+
if (Number.isFinite(mid))
|
|
159
|
+
ranked.push({ messageId: mid, score: r[i] });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
ranked.sort((a, b) => b.score - a.score);
|
|
163
|
+
const topK = opts?.topK;
|
|
164
|
+
const final = typeof topK === 'number' && topK >= 0 ? ranked.slice(0, topK) : ranked;
|
|
165
|
+
return {
|
|
166
|
+
ranked: final,
|
|
167
|
+
diagnostics: {
|
|
168
|
+
iterations,
|
|
169
|
+
converged,
|
|
170
|
+
delta,
|
|
171
|
+
messageCount: ranked.length,
|
|
172
|
+
seedCount: seedEntityKeys.length + seedFacetKeys.length,
|
|
173
|
+
emptyGraph: false,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function clamp(v, lo, hi) {
|
|
178
|
+
return Math.max(lo, Math.min(hi, v));
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=entity-ppr.js.map
|
|
@@ -64,6 +64,12 @@ export interface HybridSearchOptions {
|
|
|
64
64
|
minFtsTerms?: number;
|
|
65
65
|
/** Pre-computed embedding for the query — skips Ollama call in VectorStore.search() */
|
|
66
66
|
precomputedEmbedding?: Float32Array;
|
|
67
|
+
/**
|
|
68
|
+
* Permit VectorStore.search() to generate a query embedding inline when no
|
|
69
|
+
* precomputed embedding is available. Default false: memory recall must not
|
|
70
|
+
* put remote/local embedding generation on the search hot path.
|
|
71
|
+
*/
|
|
72
|
+
allowInlineQueryEmbedding?: boolean;
|
|
67
73
|
/**
|
|
68
74
|
* Optional reranker applied after RRF fusion. Only runs on the fused path
|
|
69
75
|
* (both FTS and KNN produced results). FTS-only and KNN-only branches are
|
|
@@ -100,6 +106,27 @@ export interface HybridSearchOptions {
|
|
|
100
106
|
* Extracts meaningful words, removes stop words, uses OR conjunction.
|
|
101
107
|
*/
|
|
102
108
|
export declare function buildFtsQuery(input: string): string;
|
|
109
|
+
/**
|
|
110
|
+
* Generic RRF helper, shared by hybridSearch() (library-side fusion) and
|
|
111
|
+
* the Sprint B entity-bridge compose lane (FTS-over-messages + PPR-over-
|
|
112
|
+
* bridge-graph). This helper does NOT change hybridSearch() semantics —
|
|
113
|
+
* the legacy in-place fusion below still owns adjacency boosting and the
|
|
114
|
+
* reranker hook for the FTS+KNN path.
|
|
115
|
+
*/
|
|
116
|
+
export interface RrfList<T> {
|
|
117
|
+
ranked: Array<{
|
|
118
|
+
key: string;
|
|
119
|
+
item: T;
|
|
120
|
+
}>;
|
|
121
|
+
weight?: number;
|
|
122
|
+
}
|
|
123
|
+
export interface RrfFusedEntry<T> {
|
|
124
|
+
key: string;
|
|
125
|
+
item: T;
|
|
126
|
+
score: number;
|
|
127
|
+
ranks: number[];
|
|
128
|
+
}
|
|
129
|
+
export declare function reciprocalRankFuse<T>(lists: Array<RrfList<T>>, k?: number): Array<RrfFusedEntry<T>>;
|
|
103
130
|
/**
|
|
104
131
|
* Hybrid search combining FTS5 keyword search and KNN vector search.
|
|
105
132
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hybrid-retrieval.d.ts","sourceRoot":"","sources":["../src/hybrid-retrieval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAQtD,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,oBAAoB,GACpB,wBAAwB,GACxB,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,WAAW,iBAAiB;IAChC,2FAA2F;IAC3F,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,cAAc,EAAE,MAAM,CAAC;CACxB;AAcD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,OAAO,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,oBAAoB,CAAC,EAAE,YAAY,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4EAA4E;IAC5E,mBAAmB,CAAC,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,CAAC,EAAE,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACzD;AAqBD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBnD;
|
|
1
|
+
{"version":3,"file":"hybrid-retrieval.d.ts","sourceRoot":"","sources":["../src/hybrid-retrieval.ts"],"names":[],"mappings":"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"}
|