engram-sdk 0.1.0 → 0.1.2
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/README.md +248 -207
- package/dist/accounts.d.ts +40 -0
- package/dist/accounts.d.ts.map +1 -0
- package/dist/accounts.js +123 -0
- package/dist/accounts.js.map +1 -0
- package/dist/cli.js +101 -53
- package/dist/cli.js.map +1 -1
- package/dist/hosted.d.ts +2 -1
- package/dist/hosted.d.ts.map +1 -1
- package/dist/hosted.js +303 -126
- package/dist/hosted.js.map +1 -1
- package/dist/server.js +34 -1
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +4 -0
- package/dist/store.js.map +1 -1
- package/dist/telemetry.d.ts +36 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +140 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/temporal.d.ts +110 -0
- package/dist/temporal.d.ts.map +1 -0
- package/dist/temporal.js +205 -0
- package/dist/temporal.js.map +1 -0
- package/dist/types.d.ts +13 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/vault.d.ts +16 -0
- package/dist/vault.d.ts.map +1 -1
- package/dist/vault.js +91 -1
- package/dist/vault.js.map +1 -1
- package/package.json +3 -2
package/dist/temporal.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* temporal.ts — Temporal Intelligence for Engram
|
|
3
|
+
*
|
|
4
|
+
* Handles fact supersession detection and recency-aware scoring.
|
|
5
|
+
* This module addresses the core weakness exposed by Letta's
|
|
6
|
+
* core-memory-update benchmark: when facts change over time,
|
|
7
|
+
* Engram needs to know which version is current.
|
|
8
|
+
*
|
|
9
|
+
* Three strategies (implement in order):
|
|
10
|
+
*
|
|
11
|
+
* 1. Contradiction detection at write time
|
|
12
|
+
* When a new memory is stored, check if it contradicts an
|
|
13
|
+
* existing memory about the same entity+topic. If so, mark
|
|
14
|
+
* the old one as `superseded` and link them with an edge.
|
|
15
|
+
*
|
|
16
|
+
* 2. Recency boost in recall scoring
|
|
17
|
+
* Add a time-decay multiplier so newer memories score higher
|
|
18
|
+
* when content similarity is close. Small effect, but helps
|
|
19
|
+
* break ties in favor of recent information.
|
|
20
|
+
*
|
|
21
|
+
* 3. Temporal spreading activation
|
|
22
|
+
* Weight graph edges by recency — when an entity activates
|
|
23
|
+
* connected memories, more recent connections fire stronger.
|
|
24
|
+
*
|
|
25
|
+
* Target: improve Letta core-memory-update from 41.9% → 65%+
|
|
26
|
+
*
|
|
27
|
+
* @module temporal
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_TEMPORAL_CONFIG = {
|
|
30
|
+
detectContradictions: true,
|
|
31
|
+
recencyBoost: {
|
|
32
|
+
enabled: true,
|
|
33
|
+
maxBoost: 0.15,
|
|
34
|
+
halfLifeDays: 7,
|
|
35
|
+
},
|
|
36
|
+
minEntityOverlap: 1,
|
|
37
|
+
contradictionSimilarityThreshold: 0.75,
|
|
38
|
+
};
|
|
39
|
+
// ── Strategy 1: Contradiction Detection ────────────────────
|
|
40
|
+
/**
|
|
41
|
+
* Check if two memories contradict each other.
|
|
42
|
+
*
|
|
43
|
+
* Heuristic approach (no LLM call):
|
|
44
|
+
* - Must share at least one entity
|
|
45
|
+
* - Must share at least one topic OR have high semantic similarity
|
|
46
|
+
* - Content must differ meaningfully (not just rephrasing)
|
|
47
|
+
*
|
|
48
|
+
* For higher accuracy, pass to LLM for verification.
|
|
49
|
+
*/
|
|
50
|
+
export function findContradictionCandidates(newMemory, existingMemories, config = DEFAULT_TEMPORAL_CONFIG) {
|
|
51
|
+
const newEntities = new Set(newMemory.entities?.map(e => e.toLowerCase()) ?? []);
|
|
52
|
+
const newTopics = new Set(newMemory.topics?.map(t => t.toLowerCase()) ?? []);
|
|
53
|
+
if (newEntities.size === 0)
|
|
54
|
+
return []; // Can't detect contradictions without entities
|
|
55
|
+
return existingMemories.filter(existing => {
|
|
56
|
+
if (existing.id === newMemory.id)
|
|
57
|
+
return false;
|
|
58
|
+
if (existing.status !== 'active')
|
|
59
|
+
return false;
|
|
60
|
+
// Must share entities
|
|
61
|
+
const existingEntities = new Set(existing.entities?.map(e => e.toLowerCase()) ?? []);
|
|
62
|
+
const sharedEntities = [...newEntities].filter(e => existingEntities.has(e));
|
|
63
|
+
if (sharedEntities.length < config.minEntityOverlap)
|
|
64
|
+
return false;
|
|
65
|
+
// Must share topics or be about the same subject
|
|
66
|
+
const existingTopics = new Set(existing.topics?.map(t => t.toLowerCase()) ?? []);
|
|
67
|
+
const sharedTopics = [...newTopics].filter(t => existingTopics.has(t));
|
|
68
|
+
const hasTopicOverlap = sharedTopics.length > 0;
|
|
69
|
+
// If no topic overlap, require higher entity overlap
|
|
70
|
+
if (!hasTopicOverlap && sharedEntities.length < 2)
|
|
71
|
+
return false;
|
|
72
|
+
// Content must actually differ (not just a duplicate)
|
|
73
|
+
if (existing.content === newMemory.content)
|
|
74
|
+
return false;
|
|
75
|
+
return true;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Use LLM to verify if two memories genuinely contradict each other.
|
|
80
|
+
*
|
|
81
|
+
* Returns null if no contradiction, or a ContradictionResult if confirmed.
|
|
82
|
+
*
|
|
83
|
+
* TODO: Implement with Gemini call
|
|
84
|
+
*/
|
|
85
|
+
export async function verifyContradiction(newMemory, oldMemory, llmCall) {
|
|
86
|
+
const prompt = `You are a fact-checking system. Determine if these two statements contradict each other (i.e., the newer one updates or corrects information in the older one).
|
|
87
|
+
|
|
88
|
+
OLDER STATEMENT (written ${oldMemory.createdAt}):
|
|
89
|
+
${oldMemory.content}
|
|
90
|
+
|
|
91
|
+
NEWER STATEMENT (written ${newMemory.createdAt}):
|
|
92
|
+
${newMemory.content}
|
|
93
|
+
|
|
94
|
+
Shared entities: ${[...new Set([...(oldMemory.entities ?? []), ...(newMemory.entities ?? [])])].join(', ')}
|
|
95
|
+
|
|
96
|
+
Respond in JSON:
|
|
97
|
+
{
|
|
98
|
+
"contradicts": true/false,
|
|
99
|
+
"confidence": 0.0-1.0,
|
|
100
|
+
"explanation": "brief explanation of what changed, or why they don't contradict"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Only mark as contradicting if the newer statement genuinely updates, corrects, or replaces information in the older one. Additions or elaborations are NOT contradictions.`;
|
|
104
|
+
try {
|
|
105
|
+
const response = await llmCall(prompt);
|
|
106
|
+
const cleaned = response.replace(/```json\n?|\n?```/g, '').trim();
|
|
107
|
+
const result = JSON.parse(cleaned);
|
|
108
|
+
if (!result.contradicts)
|
|
109
|
+
return null;
|
|
110
|
+
const newEntities = new Set(newMemory.entities?.map(e => e.toLowerCase()) ?? []);
|
|
111
|
+
const oldEntities = new Set(oldMemory.entities?.map(e => e.toLowerCase()) ?? []);
|
|
112
|
+
const sharedEntities = [...newEntities].filter(e => oldEntities.has(e));
|
|
113
|
+
const newTopics = new Set(newMemory.topics?.map(t => t.toLowerCase()) ?? []);
|
|
114
|
+
const oldTopics = new Set(oldMemory.topics?.map(t => t.toLowerCase()) ?? []);
|
|
115
|
+
const sharedTopics = [...newTopics].filter(t => oldTopics.has(t));
|
|
116
|
+
return {
|
|
117
|
+
newMemoryId: newMemory.id,
|
|
118
|
+
oldMemoryId: oldMemory.id,
|
|
119
|
+
sharedEntities,
|
|
120
|
+
sharedTopics,
|
|
121
|
+
confidence: result.confidence ?? 0.7,
|
|
122
|
+
explanation: result.explanation ?? 'Fact updated',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return null; // LLM parse failure — skip
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// ── Strategy 2: Recency Boost ──────────────────────────────
|
|
130
|
+
/**
|
|
131
|
+
* Calculate a recency boost for a memory based on its age.
|
|
132
|
+
*
|
|
133
|
+
* Uses exponential decay: boost = maxBoost * 2^(-age/halfLife)
|
|
134
|
+
*
|
|
135
|
+
* Examples (with defaults: maxBoost=0.15, halfLife=7 days):
|
|
136
|
+
* - Created today: +0.15
|
|
137
|
+
* - Created 7 days ago: +0.075
|
|
138
|
+
* - Created 14 days ago: +0.0375
|
|
139
|
+
* - Created 30 days ago: +0.009 (negligible)
|
|
140
|
+
*
|
|
141
|
+
* This is additive to the recall score, not multiplicative.
|
|
142
|
+
* It's small enough to not override strong semantic matches,
|
|
143
|
+
* but large enough to break ties between competing facts.
|
|
144
|
+
*/
|
|
145
|
+
export function calculateRecencyBoost(memory, config = DEFAULT_TEMPORAL_CONFIG.recencyBoost, now = new Date()) {
|
|
146
|
+
if (!config.enabled)
|
|
147
|
+
return 0;
|
|
148
|
+
const createdAt = new Date(memory.createdAt);
|
|
149
|
+
const ageDays = (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24);
|
|
150
|
+
if (ageDays < 0)
|
|
151
|
+
return config.maxBoost; // Future date? Give max boost
|
|
152
|
+
if (ageDays === 0)
|
|
153
|
+
return config.maxBoost;
|
|
154
|
+
// Exponential decay: halves every halfLifeDays
|
|
155
|
+
return config.maxBoost * Math.pow(2, -ageDays / config.halfLifeDays);
|
|
156
|
+
}
|
|
157
|
+
// ── Strategy 3: Temporal Spreading Activation ──────────────
|
|
158
|
+
/**
|
|
159
|
+
* Weight a graph edge by recency of the connected memory.
|
|
160
|
+
*
|
|
161
|
+
* When spreading activation traverses the memory graph,
|
|
162
|
+
* edges to more recent memories carry more activation energy.
|
|
163
|
+
*
|
|
164
|
+
* This naturally surfaces the latest version of a fact when
|
|
165
|
+
* multiple memories about the same entity exist.
|
|
166
|
+
*
|
|
167
|
+
* TODO: Integrate with vault.ts spreading activation
|
|
168
|
+
*/
|
|
169
|
+
export function temporalEdgeWeight(baseWeight, targetMemory, halfLifeDays = 14, now = new Date()) {
|
|
170
|
+
const ageDays = (now.getTime() - new Date(targetMemory.createdAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
171
|
+
const recencyFactor = Math.pow(2, -ageDays / halfLifeDays);
|
|
172
|
+
// Blend: 70% original weight + 30% recency
|
|
173
|
+
return baseWeight * (0.7 + 0.3 * recencyFactor);
|
|
174
|
+
}
|
|
175
|
+
// ── Integration Points ─────────────────────────────────────
|
|
176
|
+
//
|
|
177
|
+
// To wire this into vault.ts:
|
|
178
|
+
//
|
|
179
|
+
// 1. CONTRADICTION DETECTION (in remember() after dedup):
|
|
180
|
+
// ```
|
|
181
|
+
// if (config.temporal?.detectContradictions) {
|
|
182
|
+
// const candidates = findContradictionCandidates(memory, nearbyMemories);
|
|
183
|
+
// for (const candidate of candidates) {
|
|
184
|
+
// const result = await verifyContradiction(memory, candidate, llmCall);
|
|
185
|
+
// if (result && result.confidence >= 0.7) {
|
|
186
|
+
// this.store.updateStatus(candidate.id, 'superseded');
|
|
187
|
+
// this.store.createEdge(memory.id, candidate.id, 'supersedes', result.confidence);
|
|
188
|
+
// }
|
|
189
|
+
// }
|
|
190
|
+
// }
|
|
191
|
+
// ```
|
|
192
|
+
//
|
|
193
|
+
// 2. RECENCY BOOST (in recall() scoring, step 8):
|
|
194
|
+
// ```
|
|
195
|
+
// const recencyBoost = calculateRecencyBoost(r.memory, config.temporal?.recencyBoost);
|
|
196
|
+
// r.score += recencyBoost;
|
|
197
|
+
// ```
|
|
198
|
+
//
|
|
199
|
+
// 3. TEMPORAL SPREADING ACTIVATION (in spreadingActivation()):
|
|
200
|
+
// ```
|
|
201
|
+
// const weight = temporalEdgeWeight(edge.weight, targetMemory);
|
|
202
|
+
// ```
|
|
203
|
+
//
|
|
204
|
+
// Each can be enabled independently via TemporalConfig.
|
|
205
|
+
//# sourceMappingURL=temporal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporal.js","sourceRoot":"","sources":["../src/temporal.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -70,13 +70,13 @@ export declare const RememberInputSchema: z.ZodObject<{
|
|
|
70
70
|
agentId: z.ZodOptional<z.ZodString>;
|
|
71
71
|
evidence: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
72
72
|
}, "strip", z.ZodTypeAny, {
|
|
73
|
-
type: "
|
|
73
|
+
type: "consolidation" | "conversation" | "observation" | "inference" | "external" | "manual";
|
|
74
74
|
sessionId?: string | undefined;
|
|
75
75
|
agentId?: string | undefined;
|
|
76
76
|
evidence?: string[] | undefined;
|
|
77
77
|
}, {
|
|
78
78
|
sessionId?: string | undefined;
|
|
79
|
-
type?: "
|
|
79
|
+
type?: "consolidation" | "conversation" | "observation" | "inference" | "external" | "manual" | undefined;
|
|
80
80
|
agentId?: string | undefined;
|
|
81
81
|
evidence?: string[] | undefined;
|
|
82
82
|
}>>;
|
|
@@ -92,7 +92,7 @@ export declare const RememberInputSchema: z.ZodObject<{
|
|
|
92
92
|
visibility: "private" | "owner_agents" | "shared" | "public";
|
|
93
93
|
summary?: string | undefined;
|
|
94
94
|
source?: {
|
|
95
|
-
type: "
|
|
95
|
+
type: "consolidation" | "conversation" | "observation" | "inference" | "external" | "manual";
|
|
96
96
|
sessionId?: string | undefined;
|
|
97
97
|
agentId?: string | undefined;
|
|
98
98
|
evidence?: string[] | undefined;
|
|
@@ -110,7 +110,7 @@ export declare const RememberInputSchema: z.ZodObject<{
|
|
|
110
110
|
visibility?: "private" | "owner_agents" | "shared" | "public" | undefined;
|
|
111
111
|
source?: {
|
|
112
112
|
sessionId?: string | undefined;
|
|
113
|
-
type?: "
|
|
113
|
+
type?: "consolidation" | "conversation" | "observation" | "inference" | "external" | "manual" | undefined;
|
|
114
114
|
agentId?: string | undefined;
|
|
115
115
|
evidence?: string[] | undefined;
|
|
116
116
|
} | undefined;
|
|
@@ -191,6 +191,15 @@ export interface VaultConfig {
|
|
|
191
191
|
model?: string;
|
|
192
192
|
embeddingModel?: string;
|
|
193
193
|
};
|
|
194
|
+
/** Temporal intelligence settings (contradiction detection, recency boost) */
|
|
195
|
+
temporal?: {
|
|
196
|
+
/** Enable contradiction detection at write time (default: true when LLM is configured) */
|
|
197
|
+
detectContradictions?: boolean;
|
|
198
|
+
/** Minimum entity overlap to consider contradiction (default: 1) */
|
|
199
|
+
minEntityOverlap?: number;
|
|
200
|
+
/** Similarity threshold for contradiction candidates (default: 0.75) */
|
|
201
|
+
contradictionSimilarityThreshold?: number;
|
|
202
|
+
};
|
|
194
203
|
/** Decay settings */
|
|
195
204
|
decay?: {
|
|
196
205
|
/** Base half-life in hours for new memories (default: 168 = 1 week) */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/vault.d.ts
CHANGED
|
@@ -17,6 +17,22 @@ export declare class Vault {
|
|
|
17
17
|
* Only dedup within the same type (don't merge episodic into semantic).
|
|
18
18
|
*/
|
|
19
19
|
private dedup;
|
|
20
|
+
/**
|
|
21
|
+
* Detect contradictions: when a new memory is stored, check if it
|
|
22
|
+
* updates or replaces an existing fact about the same entity.
|
|
23
|
+
*
|
|
24
|
+
* Uses a two-phase approach:
|
|
25
|
+
* 1. Fast heuristic filter (entity/topic overlap) — no LLM cost
|
|
26
|
+
* 2. LLM verification for top candidates — one call per candidate
|
|
27
|
+
*
|
|
28
|
+
* When a contradiction is confirmed, the old memory is marked as
|
|
29
|
+
* `superseded` and linked with a `supersedes` edge. This prevents
|
|
30
|
+
* stale facts from polluting recall results.
|
|
31
|
+
*
|
|
32
|
+
* Only runs when LLM is configured. Fails silently — contradiction
|
|
33
|
+
* detection is best-effort and should never break remember().
|
|
34
|
+
*/
|
|
35
|
+
private detectContradictions;
|
|
20
36
|
/** Compute embedding and store it — can be awaited if needed */
|
|
21
37
|
computeAndStoreEmbedding(memoryId: string, content: string): Promise<void>;
|
|
22
38
|
/** Batch compute embeddings for all memories missing them */
|
package/dist/vault.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAgC,mBAAmB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACnJ,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"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"}
|
package/dist/vault.js
CHANGED
|
@@ -2,6 +2,7 @@ import path from 'path';
|
|
|
2
2
|
import { MemoryStore } from './store.js';
|
|
3
3
|
import { RememberInputSchema, RecallInputSchema } from './types.js';
|
|
4
4
|
import { extract } from './extract.js';
|
|
5
|
+
import { calculateRecencyBoost, DEFAULT_TEMPORAL_CONFIG, findContradictionCandidates, verifyContradiction } from './temporal.js';
|
|
5
6
|
// ============================================================
|
|
6
7
|
// Vault — The public API for Engram
|
|
7
8
|
// ============================================================
|
|
@@ -54,9 +55,14 @@ export class Vault {
|
|
|
54
55
|
.then(() => {
|
|
55
56
|
// Dedup check: if a very similar memory already exists, merge instead of keeping both
|
|
56
57
|
this.dedup(memory);
|
|
58
|
+
})
|
|
59
|
+
.then(() => {
|
|
60
|
+
// Contradiction detection: if this memory updates a previous fact,
|
|
61
|
+
// mark the old one as superseded. Only runs when LLM is configured.
|
|
62
|
+
return this.detectContradictions(memory);
|
|
57
63
|
})
|
|
58
64
|
.catch(err => {
|
|
59
|
-
console.warn(`Failed to
|
|
65
|
+
console.warn(`Failed to process embedding/contradictions for ${memory.id}:`, err);
|
|
60
66
|
})
|
|
61
67
|
.finally(() => {
|
|
62
68
|
this.pendingEmbeddings.delete(p);
|
|
@@ -112,6 +118,87 @@ export class Vault {
|
|
|
112
118
|
// Dedup is best-effort; don't break remember() if it fails
|
|
113
119
|
}
|
|
114
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Detect contradictions: when a new memory is stored, check if it
|
|
123
|
+
* updates or replaces an existing fact about the same entity.
|
|
124
|
+
*
|
|
125
|
+
* Uses a two-phase approach:
|
|
126
|
+
* 1. Fast heuristic filter (entity/topic overlap) — no LLM cost
|
|
127
|
+
* 2. LLM verification for top candidates — one call per candidate
|
|
128
|
+
*
|
|
129
|
+
* When a contradiction is confirmed, the old memory is marked as
|
|
130
|
+
* `superseded` and linked with a `supersedes` edge. This prevents
|
|
131
|
+
* stale facts from polluting recall results.
|
|
132
|
+
*
|
|
133
|
+
* Only runs when LLM is configured. Fails silently — contradiction
|
|
134
|
+
* detection is best-effort and should never break remember().
|
|
135
|
+
*/
|
|
136
|
+
async detectContradictions(memory) {
|
|
137
|
+
// Skip if LLM not configured or detection disabled
|
|
138
|
+
if (!this.config.llm)
|
|
139
|
+
return;
|
|
140
|
+
if (this.config.temporal?.detectContradictions === false)
|
|
141
|
+
return;
|
|
142
|
+
// Skip if memory was already superseded by dedup
|
|
143
|
+
const current = this.store.getMemoryDirect(memory.id);
|
|
144
|
+
if (!current || current.status !== 'active')
|
|
145
|
+
return;
|
|
146
|
+
// Skip memories with no entities — can't detect contradictions without them
|
|
147
|
+
if (!memory.entities || memory.entities.length === 0)
|
|
148
|
+
return;
|
|
149
|
+
try {
|
|
150
|
+
// Phase 1: Find candidates via vector similarity + entity overlap
|
|
151
|
+
const embedding = this.store.getEmbedding(memory.id);
|
|
152
|
+
if (!embedding)
|
|
153
|
+
return;
|
|
154
|
+
// Wider search than dedup — we want topically similar, not identical
|
|
155
|
+
const similar = this.store.findSimilar(embedding, 0.5, 20);
|
|
156
|
+
const candidateIds = similar
|
|
157
|
+
.filter(s => s.memoryId !== memory.id)
|
|
158
|
+
.map(s => s.memoryId);
|
|
159
|
+
if (candidateIds.length === 0)
|
|
160
|
+
return;
|
|
161
|
+
const candidateMemories = this.store.getMemoriesDirect(candidateIds)
|
|
162
|
+
.filter(m => m.status === 'active');
|
|
163
|
+
// Phase 1b: Heuristic filter — must share entities
|
|
164
|
+
const threshold = this.config.temporal?.contradictionSimilarityThreshold ?? 0.75;
|
|
165
|
+
const minOverlap = this.config.temporal?.minEntityOverlap ?? 1;
|
|
166
|
+
const filtered = findContradictionCandidates(memory, candidateMemories, {
|
|
167
|
+
detectContradictions: true,
|
|
168
|
+
recencyBoost: DEFAULT_TEMPORAL_CONFIG.recencyBoost,
|
|
169
|
+
minEntityOverlap: minOverlap,
|
|
170
|
+
contradictionSimilarityThreshold: threshold,
|
|
171
|
+
});
|
|
172
|
+
if (filtered.length === 0)
|
|
173
|
+
return;
|
|
174
|
+
// Phase 2: LLM verification — check top 3 candidates max
|
|
175
|
+
const llmCall = (prompt) => this.callLLM(this.config.llm.model ?? 'gemini-2.0-flash', prompt, this.config.llm);
|
|
176
|
+
// Only check older memories — newer ones can't be superseded by this memory
|
|
177
|
+
const olderCandidates = filtered
|
|
178
|
+
.filter(c => new Date(c.createdAt) < new Date(memory.createdAt))
|
|
179
|
+
.slice(0, 3);
|
|
180
|
+
for (const candidate of olderCandidates) {
|
|
181
|
+
const result = await verifyContradiction(memory, candidate, llmCall);
|
|
182
|
+
if (result && result.confidence >= 0.7) {
|
|
183
|
+
// Mark the old memory as superseded
|
|
184
|
+
this.store.updateStatus(candidate.id, 'superseded');
|
|
185
|
+
// Create a supersedes edge with the contradiction confidence
|
|
186
|
+
this.store.createEdge(memory.id, candidate.id, 'supersedes', result.confidence);
|
|
187
|
+
// Inherit the old memory's stability (it was a trusted fact)
|
|
188
|
+
const oldStability = candidate.stability;
|
|
189
|
+
if (oldStability > memory.stability) {
|
|
190
|
+
// The new fact inherits some credibility from the old one
|
|
191
|
+
this.store.updateMemory(memory.id, {
|
|
192
|
+
salience: Math.min(1.0, memory.salience + 0.1),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// Contradiction detection is best-effort
|
|
200
|
+
}
|
|
201
|
+
}
|
|
115
202
|
/** Compute embedding and store it — can be awaited if needed */
|
|
116
203
|
async computeAndStoreEmbedding(memoryId, content) {
|
|
117
204
|
if (!this.embedder)
|
|
@@ -343,6 +430,9 @@ export class Vault {
|
|
|
343
430
|
// Superseded/archived penalty: shouldn't appear in results
|
|
344
431
|
const statusPenalty = (r.memory.status === 'superseded' || r.memory.status === 'archived') ? 0.5 : 0;
|
|
345
432
|
r.score = r.score * (0.5 + salienceBoost + stabilityBoost + typeBonus + confidenceBonus) - statusPenalty;
|
|
433
|
+
// Recency boost: newer memories get a small additive bump.
|
|
434
|
+
// Breaks ties between competing facts about the same entity.
|
|
435
|
+
r.score += calculateRecencyBoost(r.memory, DEFAULT_TEMPORAL_CONFIG.recencyBoost);
|
|
346
436
|
}
|
|
347
437
|
// 9. Sort by score and return top N
|
|
348
438
|
results.sort((a, b) => b.score - a.score);
|