@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,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fact contradiction detection — port of KAD's fact-contradiction.ts.
|
|
3
|
+
*
|
|
4
|
+
* When new facts are stored, checks if they contradict existing facts
|
|
5
|
+
* for the same entities. Uses Claude Haiku for semantic comparison.
|
|
6
|
+
*/
|
|
7
|
+
import type { TenantContext } from '@kybernesis/brain-contracts';
|
|
8
|
+
export interface ContradictionResult {
|
|
9
|
+
contradictions: Array<{
|
|
10
|
+
oldFactId: number;
|
|
11
|
+
relationship: 'updates' | 'extends';
|
|
12
|
+
rationale: string;
|
|
13
|
+
}>;
|
|
14
|
+
checked: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Detect contradictions between a new fact and existing facts for the same
|
|
18
|
+
* entities. Returns which existing facts are updated or extended by the new one.
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectContradictions(t: TenantContext, newFact: {
|
|
21
|
+
content: string;
|
|
22
|
+
entities: string[];
|
|
23
|
+
category: string;
|
|
24
|
+
}): Promise<ContradictionResult>;
|
|
25
|
+
//# sourceMappingURL=fact-contradiction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-contradiction.d.ts","sourceRoot":"","sources":["../src/fact-contradiction.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAKjE,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,KAAK,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,SAAS,GAAG,SAAS,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAsBD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,CAAC,EAAE,aAAa,EAChB,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjE,OAAO,CAAC,mBAAmB,CAAC,CAmF9B"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fact contradiction detection — port of KAD's fact-contradiction.ts.
|
|
3
|
+
*
|
|
4
|
+
* When new facts are stored, checks if they contradict existing facts
|
|
5
|
+
* for the same entities. Uses Claude Haiku for semantic comparison.
|
|
6
|
+
*/
|
|
7
|
+
import { getFactsForEntity } from './fact-store.js';
|
|
8
|
+
import { callClaude } from './claude-call.js';
|
|
9
|
+
const RELATED_CATEGORIES = {
|
|
10
|
+
biographical: new Set(['biographical']),
|
|
11
|
+
preference: new Set(['preference']),
|
|
12
|
+
event: new Set(['event', 'temporal']),
|
|
13
|
+
relationship: new Set(['relationship']),
|
|
14
|
+
temporal: new Set(['event', 'temporal']),
|
|
15
|
+
opinion: new Set(['opinion']),
|
|
16
|
+
plan: new Set(['plan']),
|
|
17
|
+
general: new Set([
|
|
18
|
+
'biographical', 'preference', 'event', 'relationship',
|
|
19
|
+
'temporal', 'opinion', 'plan', 'general',
|
|
20
|
+
]),
|
|
21
|
+
};
|
|
22
|
+
function areCategoriesRelated(a, b) {
|
|
23
|
+
const related = RELATED_CATEGORIES[a];
|
|
24
|
+
if (!related)
|
|
25
|
+
return true;
|
|
26
|
+
return related.has(b);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Detect contradictions between a new fact and existing facts for the same
|
|
30
|
+
* entities. Returns which existing facts are updated or extended by the new one.
|
|
31
|
+
*/
|
|
32
|
+
export async function detectContradictions(t, newFact) {
|
|
33
|
+
if (!newFact.entities || newFact.entities.length === 0) {
|
|
34
|
+
return { contradictions: [], checked: 0 };
|
|
35
|
+
}
|
|
36
|
+
const candidateMap = new Map();
|
|
37
|
+
for (const entity of newFact.entities) {
|
|
38
|
+
try {
|
|
39
|
+
const facts = await getFactsForEntity(t, entity, { latestOnly: true, limit: 20 });
|
|
40
|
+
for (const fact of facts)
|
|
41
|
+
candidateMap.set(fact.id, fact);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
console.warn(`[brain-core/fact-contradiction] fetch failed for "${entity}"`, { err: String(err) });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const candidates = Array.from(candidateMap.values()).filter((f) => areCategoriesRelated(newFact.category, f.category));
|
|
48
|
+
if (candidates.length === 0)
|
|
49
|
+
return { contradictions: [], checked: 0 };
|
|
50
|
+
const toCheck = candidates.slice(0, 10);
|
|
51
|
+
try {
|
|
52
|
+
const existingList = toCheck
|
|
53
|
+
.map((f, i) => `${i + 1}. "${f.content}" (id=${f.id})`)
|
|
54
|
+
.join('\n');
|
|
55
|
+
const prompt = `Given a NEW fact and a list of EXISTING facts about the same person/entity, determine if the new fact contradicts (updates/replaces) any existing fact.
|
|
56
|
+
|
|
57
|
+
NEW FACT: "${newFact.content}"
|
|
58
|
+
|
|
59
|
+
EXISTING FACTS:
|
|
60
|
+
${existingList}
|
|
61
|
+
|
|
62
|
+
For each existing fact, determine:
|
|
63
|
+
- "updates" — the new fact replaces this (e.g., "favorite color is green" updates "favorite color is blue")
|
|
64
|
+
- "extends" — the new fact adds detail without contradicting (e.g., "lives in Brooklyn" extends "lives in NYC")
|
|
65
|
+
- "none" — no relationship
|
|
66
|
+
|
|
67
|
+
Return JSON array:
|
|
68
|
+
[{"id": 42, "relationship": "updates", "rationale": "favorite color changed"}]
|
|
69
|
+
|
|
70
|
+
Only include facts with "updates" or "extends" relationship. Return [] if no relationships found.`;
|
|
71
|
+
const response = await callClaude(prompt, { maxTokens: 512 });
|
|
72
|
+
if (!response)
|
|
73
|
+
return { contradictions: [], checked: toCheck.length };
|
|
74
|
+
const jsonMatch = response.match(/\[[\s\S]*?\]/);
|
|
75
|
+
if (!jsonMatch)
|
|
76
|
+
return { contradictions: [], checked: toCheck.length };
|
|
77
|
+
let parsed;
|
|
78
|
+
try {
|
|
79
|
+
parsed = JSON.parse(jsonMatch[0]);
|
|
80
|
+
if (!Array.isArray(parsed))
|
|
81
|
+
return { contradictions: [], checked: toCheck.length };
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return { contradictions: [], checked: toCheck.length };
|
|
85
|
+
}
|
|
86
|
+
const validIds = new Set(toCheck.map((f) => f.id));
|
|
87
|
+
const contradictions = parsed
|
|
88
|
+
.filter((item) => {
|
|
89
|
+
if (!item || typeof item !== 'object')
|
|
90
|
+
return false;
|
|
91
|
+
const o = item;
|
|
92
|
+
return (typeof o['id'] === 'number' &&
|
|
93
|
+
validIds.has(o['id']) &&
|
|
94
|
+
(o['relationship'] === 'updates' || o['relationship'] === 'extends') &&
|
|
95
|
+
typeof o['rationale'] === 'string');
|
|
96
|
+
})
|
|
97
|
+
.map((item) => ({
|
|
98
|
+
oldFactId: item.id,
|
|
99
|
+
relationship: item.relationship,
|
|
100
|
+
rationale: item.rationale,
|
|
101
|
+
}));
|
|
102
|
+
return { contradictions, checked: toCheck.length };
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
console.warn('[brain-core/fact-contradiction] detection failed', { err: String(err) });
|
|
106
|
+
return { contradictions: [], checked: toCheck.length };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=fact-contradiction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-contradiction.js","sourceRoot":"","sources":["../src/fact-contradiction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Real-time fact extraction — port of KAD's fact-extractor.ts.
|
|
3
|
+
*
|
|
4
|
+
* Lightweight inline extraction that runs after a conversation is stored.
|
|
5
|
+
* Haiku-backed, capped at 3 facts per call to keep latency low.
|
|
6
|
+
*/
|
|
7
|
+
import type { TenantContext } from '@kybernesis/brain-contracts';
|
|
8
|
+
/**
|
|
9
|
+
* Extract facts from a conversation in real-time (best-effort).
|
|
10
|
+
* Called after entity graph storage in storeConversation().
|
|
11
|
+
* Never throws — all errors are caught and logged.
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractFactsRealtime(t: TenantContext, conversationId: string, text: string, options?: {
|
|
14
|
+
entities?: string[];
|
|
15
|
+
sourcePath?: string;
|
|
16
|
+
timestamp?: string;
|
|
17
|
+
sourceType?: string;
|
|
18
|
+
arpMetadata?: {
|
|
19
|
+
project_id?: string;
|
|
20
|
+
tags?: string[];
|
|
21
|
+
classification?: 'public' | 'internal' | 'confidential' | 'pii';
|
|
22
|
+
connection_id?: string;
|
|
23
|
+
source_did?: string;
|
|
24
|
+
};
|
|
25
|
+
}): Promise<number>;
|
|
26
|
+
//# sourceMappingURL=fact-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-extractor.d.ts","sourceRoot":"","sources":["../src/fact-extractor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AA0BjE;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,CAAC,EAAE,aAAa,EAChB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IACP,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE;QACZ,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,cAAc,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,cAAc,GAAG,KAAK,CAAC;QAChE,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACE,GACL,OAAO,CAAC,MAAM,CAAC,CAgFjB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Real-time fact extraction — port of KAD's fact-extractor.ts.
|
|
3
|
+
*
|
|
4
|
+
* Lightweight inline extraction that runs after a conversation is stored.
|
|
5
|
+
* Haiku-backed, capped at 3 facts per call to keep latency low.
|
|
6
|
+
*/
|
|
7
|
+
import { SOURCE_CONFIDENCE } from '@kybernesis/brain-contracts';
|
|
8
|
+
import { storeFact, ensureFactsTable } from './fact-store.js';
|
|
9
|
+
import { detectTemporalExpiry } from './fact-temporal.js';
|
|
10
|
+
import { callClaude } from './claude-call.js';
|
|
11
|
+
const VALID_CATEGORIES = new Set([
|
|
12
|
+
'biographical', 'preference', 'event', 'relationship',
|
|
13
|
+
'temporal', 'opinion', 'plan', 'general',
|
|
14
|
+
]);
|
|
15
|
+
const REALTIME_FACT_PROMPT = `Extract 1-3 concrete facts about specific people, companies, or projects from this conversation. Only clear, verifiable facts — skip vague observations, greetings, and meta-commentary.
|
|
16
|
+
|
|
17
|
+
Each fact object has:
|
|
18
|
+
- "content": The fact statement (8-25 words, include names not pronouns)
|
|
19
|
+
- "category": One of: biographical, preference, event, relationship, temporal, opinion, plan, general
|
|
20
|
+
- "confidence": 0.5-0.9 (how confident you are)
|
|
21
|
+
- "entities": Array of person/entity names
|
|
22
|
+
|
|
23
|
+
Return a JSON array, or [] if no concrete facts.
|
|
24
|
+
|
|
25
|
+
Conversation:
|
|
26
|
+
`;
|
|
27
|
+
/**
|
|
28
|
+
* Extract facts from a conversation in real-time (best-effort).
|
|
29
|
+
* Called after entity graph storage in storeConversation().
|
|
30
|
+
* Never throws — all errors are caught and logged.
|
|
31
|
+
*/
|
|
32
|
+
export async function extractFactsRealtime(t, conversationId, text, options = {}) {
|
|
33
|
+
const { entities = [], sourcePath = `realtime://${conversationId}`, timestamp = new Date().toISOString(), sourceType = 'chat', arpMetadata, } = options;
|
|
34
|
+
// Guard: skip short conversations or those with no entities
|
|
35
|
+
if (text.length < 50 || entities.length === 0)
|
|
36
|
+
return 0;
|
|
37
|
+
await ensureFactsTable(t);
|
|
38
|
+
let factsCreated = 0;
|
|
39
|
+
try {
|
|
40
|
+
const content = text.slice(0, 2000);
|
|
41
|
+
const response = await callClaude(REALTIME_FACT_PROMPT + content, { maxTokens: 256 });
|
|
42
|
+
if (!response)
|
|
43
|
+
return 0;
|
|
44
|
+
const jsonMatch = response.match(/\[[\s\S]*\]/);
|
|
45
|
+
if (!jsonMatch)
|
|
46
|
+
return 0;
|
|
47
|
+
let rawFacts;
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
50
|
+
if (!Array.isArray(parsed))
|
|
51
|
+
return 0;
|
|
52
|
+
rawFacts = parsed;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.warn('[brain-core/fact-extractor] JSON parse failed', { err: String(err) });
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
const parentId = sourcePath.replace('channel://', '');
|
|
59
|
+
const maxConfidence = SOURCE_CONFIDENCE[sourceType] ?? 0.85;
|
|
60
|
+
for (const [i, fact] of rawFacts.slice(0, 3).entries()) {
|
|
61
|
+
if (!fact.content || fact.content.length < 10 || fact.content.length > 200)
|
|
62
|
+
continue;
|
|
63
|
+
if (!fact.entities || fact.entities.length === 0)
|
|
64
|
+
continue;
|
|
65
|
+
const category = VALID_CATEGORIES.has(fact.category) ? fact.category : 'general';
|
|
66
|
+
const confidence = Math.min(fact.confidence || 0.6, maxConfidence, 0.60);
|
|
67
|
+
const temporal = detectTemporalExpiry(fact.content, timestamp);
|
|
68
|
+
const factInput = {
|
|
69
|
+
content: fact.content,
|
|
70
|
+
sourcePath: `realtime://${parentId}/${i}`,
|
|
71
|
+
sourceConversationId: parentId,
|
|
72
|
+
entities: fact.entities,
|
|
73
|
+
timestamp,
|
|
74
|
+
confidence,
|
|
75
|
+
category: category,
|
|
76
|
+
sourceType: 'ai-extraction',
|
|
77
|
+
...(temporal.expires_at ? { expiresAt: temporal.expires_at } : {}),
|
|
78
|
+
...(arpMetadata?.project_id ? { projectId: arpMetadata.project_id } : {}),
|
|
79
|
+
tags: arpMetadata?.tags ?? [],
|
|
80
|
+
...(arpMetadata?.classification ? { classification: arpMetadata.classification } : {}),
|
|
81
|
+
...(arpMetadata?.connection_id ? { connectionId: arpMetadata.connection_id } : {}),
|
|
82
|
+
...(arpMetadata?.source_did ? { sourceDid: arpMetadata.source_did } : {}),
|
|
83
|
+
};
|
|
84
|
+
try {
|
|
85
|
+
await storeFact(t, factInput);
|
|
86
|
+
factsCreated++;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Individual fact storage is best-effort
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
console.warn('[brain-core/fact-extractor] extraction skipped', { error: String(err) });
|
|
95
|
+
}
|
|
96
|
+
return factsCreated;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=fact-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-extractor.js","sourceRoot":"","sources":["../src/fact-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fact-first retrieval engine — port of KAD's fact-retrieval.ts.
|
|
3
|
+
*
|
|
4
|
+
* 4-layer retrieval:
|
|
5
|
+
* Layer 1: Direct FTS5 + semantic search on facts
|
|
6
|
+
* Layer 2: Entity expansion (1-3 hop BFS graph traversal)
|
|
7
|
+
* Layer 2.5: Scene expansion + bridge discovery
|
|
8
|
+
* Layer 3: Supporting context (source conversation segments)
|
|
9
|
+
* Layer 4: Context optimization (prune to token budget, deduplicate)
|
|
10
|
+
*
|
|
11
|
+
* Bug Fix #2 applied here: uses sanitizeFtsQuery for all FTS MATCH calls.
|
|
12
|
+
* Bug Fix #9 applied here: wordMatchRatio denominator is FTS-query token count.
|
|
13
|
+
*/
|
|
14
|
+
import type { TenantContext } from '@kybernesis/brain-contracts';
|
|
15
|
+
export interface FactSearchOptions {
|
|
16
|
+
limit?: number;
|
|
17
|
+
tokenBudget?: number;
|
|
18
|
+
includeSupporting?: boolean;
|
|
19
|
+
maxSupportingPerFact?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface FactSearchResult {
|
|
22
|
+
facts: Array<{
|
|
23
|
+
id: number;
|
|
24
|
+
content: string;
|
|
25
|
+
category: string;
|
|
26
|
+
confidence: number;
|
|
27
|
+
timestamp: string;
|
|
28
|
+
entities: string[];
|
|
29
|
+
score: number;
|
|
30
|
+
source: 'direct' | 'entity_expansion' | 'graph_expansion' | 'scene_expansion' | 'bridge';
|
|
31
|
+
}>;
|
|
32
|
+
supporting_context: Array<{
|
|
33
|
+
content: string;
|
|
34
|
+
source_path: string;
|
|
35
|
+
timestamp: string;
|
|
36
|
+
related_fact_id: number;
|
|
37
|
+
}>;
|
|
38
|
+
assembled_context: string;
|
|
39
|
+
token_estimate: number;
|
|
40
|
+
stats: {
|
|
41
|
+
direct_facts: number;
|
|
42
|
+
expanded_facts: number;
|
|
43
|
+
graph_expanded_facts: number;
|
|
44
|
+
scene_expanded_facts: number;
|
|
45
|
+
bridge_facts: number;
|
|
46
|
+
supporting_chunks: number;
|
|
47
|
+
pruned_items: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export declare function factFirstSearch(t: TenantContext, query: string, options?: FactSearchOptions): Promise<FactSearchResult>;
|
|
51
|
+
//# sourceMappingURL=fact-retrieval.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-retrieval.d.ts","sourceRoot":"","sources":["../src/fact-retrieval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAMjE,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,QAAQ,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,QAAQ,CAAC;KAC1F,CAAC,CAAC;IACH,kBAAkB,EAAE,KAAK,CAAC;QACxB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC,CAAC;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAgUD,wBAAsB,eAAe,CACnC,CAAC,EAAE,aAAa,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CA4I3B"}
|