@kybernesis/brain-core 0.1.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/dist/claude-call.d.ts +37 -0
- package/dist/claude-call.d.ts.map +1 -0
- package/dist/claude-call.js +55 -0
- package/dist/claude-call.js.map +1 -0
- package/dist/entity-graph.d.ts +79 -0
- package/dist/entity-graph.d.ts.map +1 -0
- package/dist/entity-graph.js +611 -0
- package/dist/entity-graph.js.map +1 -0
- package/dist/fact-contradiction.d.ts +25 -0
- package/dist/fact-contradiction.d.ts.map +1 -0
- package/dist/fact-contradiction.js +109 -0
- package/dist/fact-contradiction.js.map +1 -0
- package/dist/fact-extractor.d.ts +26 -0
- package/dist/fact-extractor.d.ts.map +1 -0
- package/dist/fact-extractor.js +98 -0
- package/dist/fact-extractor.js.map +1 -0
- package/dist/fact-retrieval.d.ts +51 -0
- package/dist/fact-retrieval.d.ts.map +1 -0
- package/dist/fact-retrieval.js +401 -0
- package/dist/fact-retrieval.js.map +1 -0
- package/dist/fact-store.d.ts +26 -0
- package/dist/fact-store.d.ts.map +1 -0
- package/dist/fact-store.js +181 -0
- package/dist/fact-store.js.map +1 -0
- package/dist/fact-temporal.d.ts +20 -0
- package/dist/fact-temporal.d.ts.map +1 -0
- package/dist/fact-temporal.js +79 -0
- package/dist/fact-temporal.js.map +1 -0
- package/dist/fts-sanitizer.d.ts +32 -0
- package/dist/fts-sanitizer.d.ts.map +1 -0
- package/dist/fts-sanitizer.js +61 -0
- package/dist/fts-sanitizer.js.map +1 -0
- package/dist/hybrid-search.d.ts +44 -0
- package/dist/hybrid-search.d.ts.map +1 -0
- package/dist/hybrid-search.js +410 -0
- package/dist/hybrid-search.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/ops.d.ts +28 -0
- package/dist/ops.d.ts.map +1 -0
- package/dist/ops.js +307 -0
- package/dist/ops.js.map +1 -0
- package/dist/queue.d.ts +13 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +28 -0
- package/dist/queue.js.map +1 -0
- package/dist/relationship-extractor.d.ts +38 -0
- package/dist/relationship-extractor.d.ts.map +1 -0
- package/dist/relationship-extractor.js +119 -0
- package/dist/relationship-extractor.js.map +1 -0
- package/dist/sleep/config.d.ts +47 -0
- package/dist/sleep/config.d.ts.map +1 -0
- package/dist/sleep/config.js +46 -0
- package/dist/sleep/config.js.map +1 -0
- package/dist/sleep/db.d.ts +16 -0
- package/dist/sleep/db.d.ts.map +1 -0
- package/dist/sleep/db.js +114 -0
- package/dist/sleep/db.js.map +1 -0
- package/dist/sleep/index.d.ts +69 -0
- package/dist/sleep/index.d.ts.map +1 -0
- package/dist/sleep/index.js +99 -0
- package/dist/sleep/index.js.map +1 -0
- package/dist/sleep/steps/consolidate.d.ts +19 -0
- package/dist/sleep/steps/consolidate.d.ts.map +1 -0
- package/dist/sleep/steps/consolidate.js +74 -0
- package/dist/sleep/steps/consolidate.js.map +1 -0
- package/dist/sleep/steps/decay.d.ts +19 -0
- package/dist/sleep/steps/decay.d.ts.map +1 -0
- package/dist/sleep/steps/decay.js +121 -0
- package/dist/sleep/steps/decay.js.map +1 -0
- package/dist/sleep/steps/entity-hygiene.d.ts +29 -0
- package/dist/sleep/steps/entity-hygiene.d.ts.map +1 -0
- package/dist/sleep/steps/entity-hygiene.js +452 -0
- package/dist/sleep/steps/entity-hygiene.js.map +1 -0
- package/dist/sleep/steps/link.d.ts +20 -0
- package/dist/sleep/steps/link.d.ts.map +1 -0
- package/dist/sleep/steps/link.js +216 -0
- package/dist/sleep/steps/link.js.map +1 -0
- package/dist/sleep/steps/observe.d.ts +17 -0
- package/dist/sleep/steps/observe.d.ts.map +1 -0
- package/dist/sleep/steps/observe.js +192 -0
- package/dist/sleep/steps/observe.js.map +1 -0
- package/dist/sleep/steps/profile.d.ts +15 -0
- package/dist/sleep/steps/profile.d.ts.map +1 -0
- package/dist/sleep/steps/profile.js +26 -0
- package/dist/sleep/steps/profile.js.map +1 -0
- package/dist/sleep/steps/reasoning.d.ts +19 -0
- package/dist/sleep/steps/reasoning.d.ts.map +1 -0
- package/dist/sleep/steps/reasoning.js +173 -0
- package/dist/sleep/steps/reasoning.js.map +1 -0
- package/dist/sleep/steps/summarize.d.ts +21 -0
- package/dist/sleep/steps/summarize.d.ts.map +1 -0
- package/dist/sleep/steps/summarize.js +206 -0
- package/dist/sleep/steps/summarize.js.map +1 -0
- package/dist/sleep/steps/tag.d.ts +16 -0
- package/dist/sleep/steps/tag.d.ts.map +1 -0
- package/dist/sleep/steps/tag.js +84 -0
- package/dist/sleep/steps/tag.js.map +1 -0
- package/dist/sleep/steps/tier.d.ts +18 -0
- package/dist/sleep/steps/tier.d.ts.map +1 -0
- package/dist/sleep/steps/tier.js +112 -0
- package/dist/sleep/steps/tier.js.map +1 -0
- package/dist/sleep/utils/checkpoint.d.ts +11 -0
- package/dist/sleep/utils/checkpoint.d.ts.map +1 -0
- package/dist/sleep/utils/checkpoint.js +26 -0
- package/dist/sleep/utils/checkpoint.js.map +1 -0
- package/dist/sleep/utils/jaccard.d.ts +7 -0
- package/dist/sleep/utils/jaccard.d.ts.map +1 -0
- package/dist/sleep/utils/jaccard.js +19 -0
- package/dist/sleep/utils/jaccard.js.map +1 -0
- package/dist/store-conversation.d.ts +29 -0
- package/dist/store-conversation.d.ts.map +1 -0
- package/dist/store-conversation.js +227 -0
- package/dist/store-conversation.js.map +1 -0
- package/dist/timeline.d.ts +50 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +389 -0
- package/dist/timeline.js.map +1 -0
- package/dist/user-profile.d.ts +30 -0
- package/dist/user-profile.d.ts.map +1 -0
- package/dist/user-profile.js +147 -0
- package/dist/user-profile.js.map +1 -0
- package/dist/vectors.d.ts +56 -0
- package/dist/vectors.d.ts.map +1 -0
- package/dist/vectors.js +132 -0
- package/dist/vectors.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fact temporal expiry detection — port of KAD's fact-temporal.ts.
|
|
3
|
+
*
|
|
4
|
+
* Detects time-bound facts ("I have an exam tomorrow") and computes
|
|
5
|
+
* absolute expiry dates so they automatically disappear from retrieval.
|
|
6
|
+
* Pure heuristic — no LLM needed.
|
|
7
|
+
*/
|
|
8
|
+
export interface TemporalResult {
|
|
9
|
+
is_temporal: boolean;
|
|
10
|
+
expires_at: string | null;
|
|
11
|
+
temporal_expression: string | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Detect time-bound expressions in a fact and compute an absolute expiry.
|
|
15
|
+
*
|
|
16
|
+
* @param factContent - The extracted fact text
|
|
17
|
+
* @param factTimestamp - ISO 8601 timestamp of the source conversation
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectTemporalExpiry(factContent: string, factTimestamp: string): TemporalResult;
|
|
20
|
+
//# sourceMappingURL=fact-temporal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-temporal.d.ts","sourceRoot":"","sources":["../src/fact-temporal.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AA+BD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,cAAc,CA2C/F"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fact temporal expiry detection — port of KAD's fact-temporal.ts.
|
|
3
|
+
*
|
|
4
|
+
* Detects time-bound facts ("I have an exam tomorrow") and computes
|
|
5
|
+
* absolute expiry dates so they automatically disappear from retrieval.
|
|
6
|
+
* Pure heuristic — no LLM needed.
|
|
7
|
+
*/
|
|
8
|
+
const DAY_NAMES = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
|
|
9
|
+
function addDays(date, days) {
|
|
10
|
+
const result = new Date(date);
|
|
11
|
+
result.setUTCDate(result.getUTCDate() + days);
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
function endOfMonth(year, month) {
|
|
15
|
+
return new Date(Date.UTC(year, month, 1));
|
|
16
|
+
}
|
|
17
|
+
function nextWeekday(from, targetDay) {
|
|
18
|
+
const current = from.getUTCDay();
|
|
19
|
+
let diff = targetDay - current;
|
|
20
|
+
if (diff <= 0)
|
|
21
|
+
diff += 7;
|
|
22
|
+
return addDays(from, diff);
|
|
23
|
+
}
|
|
24
|
+
function startOfDayUTC(date) {
|
|
25
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
|
26
|
+
}
|
|
27
|
+
function result(expiresAt, expression) {
|
|
28
|
+
return { is_temporal: true, expires_at: expiresAt.toISOString(), temporal_expression: expression };
|
|
29
|
+
}
|
|
30
|
+
const NO_MATCH = { is_temporal: false, expires_at: null, temporal_expression: null };
|
|
31
|
+
/**
|
|
32
|
+
* Detect time-bound expressions in a fact and compute an absolute expiry.
|
|
33
|
+
*
|
|
34
|
+
* @param factContent - The extracted fact text
|
|
35
|
+
* @param factTimestamp - ISO 8601 timestamp of the source conversation
|
|
36
|
+
*/
|
|
37
|
+
export function detectTemporalExpiry(factContent, factTimestamp) {
|
|
38
|
+
const text = factContent.toLowerCase();
|
|
39
|
+
const base = startOfDayUTC(new Date(factTimestamp));
|
|
40
|
+
if (/\bthis\s+weekend\b/.test(text)) {
|
|
41
|
+
return result(nextWeekday(base, 1), 'this weekend');
|
|
42
|
+
}
|
|
43
|
+
if (/\bnext\s+week\b/.test(text)) {
|
|
44
|
+
return result(addDays(base, 14), 'next week');
|
|
45
|
+
}
|
|
46
|
+
if (/\bthis\s+week\b/.test(text)) {
|
|
47
|
+
return result(addDays(base, 7), 'this week');
|
|
48
|
+
}
|
|
49
|
+
if (/\bnext\s+month\b/.test(text)) {
|
|
50
|
+
const nextMonthIdx = base.getUTCMonth() + 2;
|
|
51
|
+
const year = nextMonthIdx > 12 ? base.getUTCFullYear() + 1 : base.getUTCFullYear();
|
|
52
|
+
const month = nextMonthIdx > 12 ? nextMonthIdx - 12 : nextMonthIdx;
|
|
53
|
+
return result(endOfMonth(year, month), 'next month');
|
|
54
|
+
}
|
|
55
|
+
if (/\bthis\s+month\b/.test(text)) {
|
|
56
|
+
return result(endOfMonth(base.getUTCFullYear(), base.getUTCMonth() + 1), 'this month');
|
|
57
|
+
}
|
|
58
|
+
if (/\btomorrow\b/.test(text)) {
|
|
59
|
+
return result(addDays(base, 2), 'tomorrow');
|
|
60
|
+
}
|
|
61
|
+
if (/\b(today|tonight)\b/.test(text)) {
|
|
62
|
+
return result(addDays(base, 1), text.match(/\b(today|tonight)\b/)[0]);
|
|
63
|
+
}
|
|
64
|
+
for (let i = 0; i < DAY_NAMES.length; i++) {
|
|
65
|
+
const dayName = DAY_NAMES[i];
|
|
66
|
+
const thisPattern = new RegExp(`\\bthis\\s+${dayName}\\b`);
|
|
67
|
+
const nextPattern = new RegExp(`\\bnext\\s+${dayName}\\b`);
|
|
68
|
+
if (thisPattern.test(text) || nextPattern.test(text)) {
|
|
69
|
+
const target = nextWeekday(base, i);
|
|
70
|
+
return result(addDays(target, 1), text.match(thisPattern)?.[0] || text.match(nextPattern)[0]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (/\bupcoming\b/.test(text))
|
|
74
|
+
return result(addDays(base, 30), 'upcoming');
|
|
75
|
+
if (/\bsoon\b/.test(text))
|
|
76
|
+
return result(addDays(base, 14), 'soon');
|
|
77
|
+
return NO_MATCH;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=fact-temporal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-temporal.js","sourceRoot":"","sources":["../src/fact-temporal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FTS5 query sanitizer — Bug Fix #2.
|
|
3
|
+
*
|
|
4
|
+
* KAD's naive sanitizer (`replace(/[?.,!'"]/g, '')`) silently breaks on:
|
|
5
|
+
* - Hyphenated terms: "post-mortem" → FTS5 reads as "post NOT mortem"
|
|
6
|
+
* - Unicode: "café" — the quote-strip mangled accented chars
|
|
7
|
+
* - FTS5 operator tokens: bare AND/OR/NOT/NEAR are taken as operators
|
|
8
|
+
* - Quoted phrases: embedded quotes broke the MATCH string
|
|
9
|
+
*
|
|
10
|
+
* This helper is the single shared sanitizer for all three FTS call sites:
|
|
11
|
+
* 1. `searchFactsFts` in fact-store.ts
|
|
12
|
+
* 2. `searchFactsDirect` in fact-retrieval.ts
|
|
13
|
+
* 3. `queryTimeline` FTS MATCH path in timeline.ts
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Convert a natural-language query into a safe FTS5 MATCH expression.
|
|
17
|
+
*
|
|
18
|
+
* Strategy:
|
|
19
|
+
* - Normalize unicode (NFC)
|
|
20
|
+
* - Split on whitespace
|
|
21
|
+
* - Strip leading/trailing punctuation from each token
|
|
22
|
+
* - Replace hyphens with spaces (FTS5 leading `-` = NOT operator)
|
|
23
|
+
* - Drop FTS5 reserved operator words
|
|
24
|
+
* - Drop tokens shorter than 2 chars
|
|
25
|
+
* - Double-quote each token so FTS5 treats it as a literal phrase
|
|
26
|
+
* - Join with OR for broad matching
|
|
27
|
+
*
|
|
28
|
+
* Returns empty string when no usable tokens remain; callers must
|
|
29
|
+
* skip the FTS query entirely on empty string to avoid a syntax error.
|
|
30
|
+
*/
|
|
31
|
+
export declare function sanitizeFtsQuery(query: string): string;
|
|
32
|
+
//# sourceMappingURL=fts-sanitizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fts-sanitizer.d.ts","sourceRoot":"","sources":["../src/fts-sanitizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA2BtD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FTS5 query sanitizer — Bug Fix #2.
|
|
3
|
+
*
|
|
4
|
+
* KAD's naive sanitizer (`replace(/[?.,!'"]/g, '')`) silently breaks on:
|
|
5
|
+
* - Hyphenated terms: "post-mortem" → FTS5 reads as "post NOT mortem"
|
|
6
|
+
* - Unicode: "café" — the quote-strip mangled accented chars
|
|
7
|
+
* - FTS5 operator tokens: bare AND/OR/NOT/NEAR are taken as operators
|
|
8
|
+
* - Quoted phrases: embedded quotes broke the MATCH string
|
|
9
|
+
*
|
|
10
|
+
* This helper is the single shared sanitizer for all three FTS call sites:
|
|
11
|
+
* 1. `searchFactsFts` in fact-store.ts
|
|
12
|
+
* 2. `searchFactsDirect` in fact-retrieval.ts
|
|
13
|
+
* 3. `queryTimeline` FTS MATCH path in timeline.ts
|
|
14
|
+
*/
|
|
15
|
+
const FTS5_RESERVED = new Set(['NEAR', 'AND', 'OR', 'NOT']);
|
|
16
|
+
/**
|
|
17
|
+
* Convert a natural-language query into a safe FTS5 MATCH expression.
|
|
18
|
+
*
|
|
19
|
+
* Strategy:
|
|
20
|
+
* - Normalize unicode (NFC)
|
|
21
|
+
* - Split on whitespace
|
|
22
|
+
* - Strip leading/trailing punctuation from each token
|
|
23
|
+
* - Replace hyphens with spaces (FTS5 leading `-` = NOT operator)
|
|
24
|
+
* - Drop FTS5 reserved operator words
|
|
25
|
+
* - Drop tokens shorter than 2 chars
|
|
26
|
+
* - Double-quote each token so FTS5 treats it as a literal phrase
|
|
27
|
+
* - Join with OR for broad matching
|
|
28
|
+
*
|
|
29
|
+
* Returns empty string when no usable tokens remain; callers must
|
|
30
|
+
* skip the FTS query entirely on empty string to avoid a syntax error.
|
|
31
|
+
*/
|
|
32
|
+
export function sanitizeFtsQuery(query) {
|
|
33
|
+
const normalized = query.normalize('NFC');
|
|
34
|
+
const rawTokens = normalized.split(/\s+/).filter(Boolean);
|
|
35
|
+
const quoted = [];
|
|
36
|
+
for (const raw of rawTokens) {
|
|
37
|
+
// Strip leading/trailing punctuation (preserve inner chars including unicode)
|
|
38
|
+
const stripped = raw.replace(/^[.,!?;:'"()\[\]{}|\\^*]+|[.,!?;:'"()\[\]{}|\\^*]+$/g, '');
|
|
39
|
+
if (!stripped)
|
|
40
|
+
continue;
|
|
41
|
+
// Replace hyphens with spaces — FTS5 treats leading "-" as NOT operator
|
|
42
|
+
const dehyphenated = stripped.replace(/-/g, ' ').trim();
|
|
43
|
+
if (!dehyphenated)
|
|
44
|
+
continue;
|
|
45
|
+
// Split any sub-tokens produced by hyphen removal
|
|
46
|
+
for (const sub of dehyphenated.split(/\s+/)) {
|
|
47
|
+
if (sub.length < 2)
|
|
48
|
+
continue;
|
|
49
|
+
// Skip bare FTS5 reserved words
|
|
50
|
+
if (FTS5_RESERVED.has(sub.toUpperCase()))
|
|
51
|
+
continue;
|
|
52
|
+
// Escape embedded double-quotes and wrap in quotes
|
|
53
|
+
const escaped = sub.replace(/"/g, '');
|
|
54
|
+
if (!escaped)
|
|
55
|
+
continue;
|
|
56
|
+
quoted.push(`"${escaped}"`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return quoted.join(' OR ');
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=fts-sanitizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fts-sanitizer.js","sourceRoot":"","sources":["../src/fts-sanitizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AAE5D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,8EAA8E;QAC9E,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,sDAAsD,EAAE,EAAE,CAAC,CAAC;QACzF,IAAI,CAAC,QAAQ;YAAE,SAAS;QAExB,wEAAwE;QACxE,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACxD,IAAI,CAAC,YAAY;YAAE,SAAS;QAE5B,kDAAkD;QAClD,KAAK,MAAM,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS;YAC7B,gCAAgC;YAChC,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBAAE,SAAS;YACnD,mDAAmD;YACnD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACtC,IAAI,CAAC,OAAO;gBAAE,SAAS;YACvB,MAAM,CAAC,IAAI,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid search — port of KAD's hybrid-search.ts.
|
|
3
|
+
*
|
|
4
|
+
* Combines semantic search (vectors), keyword search (FTS5), and temporal
|
|
5
|
+
* search. Uses Reciprocal Rank Fusion (RRF k=60) to merge ranked lists.
|
|
6
|
+
*
|
|
7
|
+
* Bug Fix #3: the null `getSleepDb` stub that made sleep-edge enrichment
|
|
8
|
+
* dead code has been deleted. Uses `getDb(t, 'sleep')` directly.
|
|
9
|
+
*/
|
|
10
|
+
import type { TenantContext } from '@kybernesis/brain-contracts';
|
|
11
|
+
export interface HybridSearchResult {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
content: string;
|
|
15
|
+
source_path: string;
|
|
16
|
+
timestamp: string;
|
|
17
|
+
type: string;
|
|
18
|
+
tier?: string;
|
|
19
|
+
priority?: number;
|
|
20
|
+
tags?: string[];
|
|
21
|
+
semanticScore: number;
|
|
22
|
+
metadataScore: number;
|
|
23
|
+
hybridScore: number;
|
|
24
|
+
matchType: 'semantic' | 'keyword' | 'both';
|
|
25
|
+
relatedMemories?: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface HybridSearchOptions {
|
|
28
|
+
limit?: number;
|
|
29
|
+
tier?: 'hot' | 'warm' | 'archive' | 'all';
|
|
30
|
+
minPriority?: number;
|
|
31
|
+
includeRelated?: boolean;
|
|
32
|
+
semanticWeight?: number;
|
|
33
|
+
metadataWeight?: number;
|
|
34
|
+
type?: 'conversation' | 'idea' | 'file' | 'transcript' | 'note';
|
|
35
|
+
entity?: string;
|
|
36
|
+
entityMatch?: 'all' | 'any';
|
|
37
|
+
after?: Date;
|
|
38
|
+
before?: Date;
|
|
39
|
+
expandQuery?: boolean;
|
|
40
|
+
factFirst?: boolean;
|
|
41
|
+
rerank?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export declare function hybridSearch(t: TenantContext, query: string, options?: HybridSearchOptions): Promise<HybridSearchResult[]>;
|
|
44
|
+
//# sourceMappingURL=hybrid-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hybrid-search.d.ts","sourceRoot":"","sources":["../src/hybrid-search.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAKjE,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;IAC3C,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,CAAC;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC5B,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA2QD,wBAAsB,YAAY,CAChC,CAAC,EAAE,aAAa,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA8K/B"}
|