hippo-memory 0.36.0 → 0.37.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/README.md +16 -0
- package/dist/api.d.ts +20 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +23 -3
- package/dist/api.js.map +1 -1
- package/dist/benchmarks/e1.3/incident-recall-eval.js +74 -0
- package/dist/benchmarks/e1.3/incident-recall-eval.js.map +1 -0
- package/dist/benchmarks/e1.3/scenarios.json +2587 -0
- package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +102 -0
- package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +1 -0
- package/dist/cli.js +82 -0
- package/dist/cli.js.map +1 -1
- package/dist/connectors/slack/backfill.d.ts +42 -0
- package/dist/connectors/slack/backfill.d.ts.map +1 -0
- package/dist/connectors/slack/backfill.js +76 -0
- package/dist/connectors/slack/backfill.js.map +1 -0
- package/dist/connectors/slack/deletion.d.ts +14 -0
- package/dist/connectors/slack/deletion.d.ts.map +1 -0
- package/dist/connectors/slack/deletion.js +46 -0
- package/dist/connectors/slack/deletion.js.map +1 -0
- package/dist/connectors/slack/dlq.d.ts +21 -0
- package/dist/connectors/slack/dlq.d.ts.map +1 -0
- package/dist/connectors/slack/dlq.js +23 -0
- package/dist/connectors/slack/dlq.js.map +1 -0
- package/dist/connectors/slack/idempotency.d.ts +5 -0
- package/dist/connectors/slack/idempotency.d.ts.map +1 -0
- package/dist/connectors/slack/idempotency.js +13 -0
- package/dist/connectors/slack/idempotency.js.map +1 -0
- package/dist/connectors/slack/ingest.d.ts +27 -0
- package/dist/connectors/slack/ingest.d.ts.map +1 -0
- package/dist/connectors/slack/ingest.js +48 -0
- package/dist/connectors/slack/ingest.js.map +1 -0
- package/dist/connectors/slack/ratelimit.d.ts +9 -0
- package/dist/connectors/slack/ratelimit.d.ts.map +1 -0
- package/dist/connectors/slack/ratelimit.js +18 -0
- package/dist/connectors/slack/ratelimit.js.map +1 -0
- package/dist/connectors/slack/scope.d.ts +16 -0
- package/dist/connectors/slack/scope.d.ts.map +1 -0
- package/dist/connectors/slack/scope.js +13 -0
- package/dist/connectors/slack/scope.js.map +1 -0
- package/dist/connectors/slack/signature.d.ts +12 -0
- package/dist/connectors/slack/signature.d.ts.map +1 -0
- package/dist/connectors/slack/signature.js +20 -0
- package/dist/connectors/slack/signature.js.map +1 -0
- package/dist/connectors/slack/tenant-routing.d.ts +13 -0
- package/dist/connectors/slack/tenant-routing.d.ts.map +1 -0
- package/dist/connectors/slack/tenant-routing.js +17 -0
- package/dist/connectors/slack/tenant-routing.js.map +1 -0
- package/dist/connectors/slack/transform.d.ts +20 -0
- package/dist/connectors/slack/transform.d.ts.map +1 -0
- package/dist/connectors/slack/transform.js +31 -0
- package/dist/connectors/slack/transform.js.map +1 -0
- package/dist/connectors/slack/types.d.ts +35 -0
- package/dist/connectors/slack/types.d.ts.map +1 -0
- package/dist/connectors/slack/types.js +23 -0
- package/dist/connectors/slack/types.js.map +1 -0
- package/dist/connectors/slack/web-client.d.ts +12 -0
- package/dist/connectors/slack/web-client.d.ts.map +1 -0
- package/dist/connectors/slack/web-client.js +43 -0
- package/dist/connectors/slack/web-client.js.map +1 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +46 -1
- package/dist/db.js.map +1 -1
- package/dist/importers.js +3 -3
- package/dist/importers.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +174 -2
- package/dist/server.js.map +1 -1
- package/dist/src/ambient.js +147 -0
- package/dist/src/ambient.js.map +1 -0
- package/dist/src/api.js +343 -0
- package/dist/src/api.js.map +1 -0
- package/dist/src/audit.js +152 -0
- package/dist/src/audit.js.map +1 -0
- package/dist/src/auth.js +65 -0
- package/dist/src/auth.js.map +1 -0
- package/dist/src/autolearn.js +143 -0
- package/dist/src/autolearn.js.map +1 -0
- package/dist/src/capture.js +512 -0
- package/dist/src/capture.js.map +1 -0
- package/dist/src/cli.js +4971 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/client.js +181 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/config.js +108 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/connectors/slack/backfill.js +76 -0
- package/dist/src/connectors/slack/backfill.js.map +1 -0
- package/dist/src/connectors/slack/deletion.js +46 -0
- package/dist/src/connectors/slack/deletion.js.map +1 -0
- package/dist/src/connectors/slack/dlq.js +23 -0
- package/dist/src/connectors/slack/dlq.js.map +1 -0
- package/dist/src/connectors/slack/idempotency.js +13 -0
- package/dist/src/connectors/slack/idempotency.js.map +1 -0
- package/dist/src/connectors/slack/ingest.js +48 -0
- package/dist/src/connectors/slack/ingest.js.map +1 -0
- package/dist/src/connectors/slack/ratelimit.js +18 -0
- package/dist/src/connectors/slack/ratelimit.js.map +1 -0
- package/dist/src/connectors/slack/scope.js +13 -0
- package/dist/src/connectors/slack/scope.js.map +1 -0
- package/dist/src/connectors/slack/signature.js +20 -0
- package/dist/src/connectors/slack/signature.js.map +1 -0
- package/dist/src/connectors/slack/tenant-routing.js +17 -0
- package/dist/src/connectors/slack/tenant-routing.js.map +1 -0
- package/dist/src/connectors/slack/transform.js +31 -0
- package/dist/src/connectors/slack/transform.js.map +1 -0
- package/dist/src/connectors/slack/types.js +23 -0
- package/dist/src/connectors/slack/types.js.map +1 -0
- package/dist/src/connectors/slack/web-client.js +43 -0
- package/dist/src/connectors/slack/web-client.js.map +1 -0
- package/dist/src/consolidate.js +517 -0
- package/dist/src/consolidate.js.map +1 -0
- package/dist/src/dag.js +104 -0
- package/dist/src/dag.js.map +1 -0
- package/dist/src/dashboard.js +409 -0
- package/dist/src/dashboard.js.map +1 -0
- package/dist/src/db.js +584 -0
- package/dist/src/db.js.map +1 -0
- package/dist/src/embeddings.js +344 -0
- package/dist/src/embeddings.js.map +1 -0
- package/dist/src/eval-suite.js +289 -0
- package/dist/src/eval-suite.js.map +1 -0
- package/dist/src/eval.js +187 -0
- package/dist/src/eval.js.map +1 -0
- package/dist/src/extract.js +87 -0
- package/dist/src/extract.js.map +1 -0
- package/dist/src/handoff.js +30 -0
- package/dist/src/handoff.js.map +1 -0
- package/dist/src/hooks.js +582 -0
- package/dist/src/hooks.js.map +1 -0
- package/dist/src/importers.js +399 -0
- package/dist/src/importers.js.map +1 -0
- package/dist/src/index.js +25 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/invalidation.js +94 -0
- package/dist/src/invalidation.js.map +1 -0
- package/dist/src/mcp/framing.js +45 -0
- package/dist/src/mcp/framing.js.map +1 -0
- package/dist/src/mcp/server.js +510 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/memory.js +280 -0
- package/dist/src/memory.js.map +1 -0
- package/dist/src/multihop.js +32 -0
- package/dist/src/multihop.js.map +1 -0
- package/dist/src/path-context.js +32 -0
- package/dist/src/path-context.js.map +1 -0
- package/dist/src/physics-config.js +26 -0
- package/dist/src/physics-config.js.map +1 -0
- package/dist/src/physics-state.js +163 -0
- package/dist/src/physics-state.js.map +1 -0
- package/dist/src/physics.js +361 -0
- package/dist/src/physics.js.map +1 -0
- package/dist/src/postinstall.js +68 -0
- package/dist/src/postinstall.js.map +1 -0
- package/dist/src/raw-archive.js +72 -0
- package/dist/src/raw-archive.js.map +1 -0
- package/dist/src/refine-llm.js +147 -0
- package/dist/src/refine-llm.js.map +1 -0
- package/dist/src/replay.js +117 -0
- package/dist/src/replay.js.map +1 -0
- package/dist/src/salience.js +74 -0
- package/dist/src/salience.js.map +1 -0
- package/dist/src/scheduler.js +67 -0
- package/dist/src/scheduler.js.map +1 -0
- package/dist/src/scope.js +35 -0
- package/dist/src/scope.js.map +1 -0
- package/dist/src/search.js +801 -0
- package/dist/src/search.js.map +1 -0
- package/dist/src/server-detect.js +70 -0
- package/dist/src/server-detect.js.map +1 -0
- package/dist/src/server.js +784 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/shared.js +309 -0
- package/dist/src/shared.js.map +1 -0
- package/dist/src/sso.js +22 -0
- package/dist/src/sso.js.map +1 -0
- package/dist/src/store.js +1390 -0
- package/dist/src/store.js.map +1 -0
- package/dist/src/tenant.js +17 -0
- package/dist/src/tenant.js.map +1 -0
- package/dist/src/trace.js +64 -0
- package/dist/src/trace.js.map +1 -0
- package/dist/src/working-memory.js +149 -0
- package/dist/src/working-memory.js.map +1 -0
- package/dist/src/yaml.js +98 -0
- package/dist/src/yaml.js.map +1 -0
- package/dist/store.d.ts +9 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +30 -2
- package/dist/store.js.map +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
- package/dist/import.d.ts +0 -31
- package/dist/import.d.ts.map +0 -1
- package/dist/import.js +0 -307
- package/dist/import.js.map +0 -1
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consolidation engine ("Sleep") for Hippo.
|
|
3
|
+
*
|
|
4
|
+
* Steps:
|
|
5
|
+
* 1. Decay pass - remove entries below strength threshold
|
|
6
|
+
* 2. Merge pass - find episodic entries with high text overlap, create semantic summaries
|
|
7
|
+
* 3. Stats tracking
|
|
8
|
+
*/
|
|
9
|
+
import { Layer, calculateStrength, createMemory, resolveConfidence } from './memory.js';
|
|
10
|
+
import { loadAllEntries, batchWriteAndDelete, appendConsolidationRun, replaceDetectedConflicts, loadSessionDecayContext, incrementSleepCount, findPromotableSessions, traceExistsForSession, listSessionEvents, } from './store.js';
|
|
11
|
+
import { textOverlap, markRetrieved } from './search.js';
|
|
12
|
+
import { openHippoDb, closeHippoDb } from './db.js';
|
|
13
|
+
import { loadPhysicsState, savePhysicsState, refreshParticleProperties } from './physics-state.js';
|
|
14
|
+
import { simulate } from './physics.js';
|
|
15
|
+
import { loadConfig } from './config.js';
|
|
16
|
+
import { sampleForReplay } from './replay.js';
|
|
17
|
+
import { renderTraceContent } from './trace.js';
|
|
18
|
+
const DECAY_THRESHOLD = 0.05;
|
|
19
|
+
const MERGE_OVERLAP_THRESHOLD = 0.35; // Jaccard similarity for "related"
|
|
20
|
+
const MERGE_MIN_CLUSTER = 2; // minimum cluster size to merge
|
|
21
|
+
// Contradictions should be gated by content overlap, not shared tags. Tags like
|
|
22
|
+
// `feedback` / `policy` are too coarse and can make unrelated rules look like
|
|
23
|
+
// conflicts before the polarity heuristics run.
|
|
24
|
+
// Jaccard threshold on stopword-filtered tokens. Only applied after a polarity
|
|
25
|
+
// signal has already been detected (explicit pair or inferred negation), so
|
|
26
|
+
// this just filters out drive-by topic similarity, not semantic drift.
|
|
27
|
+
const CONFLICT_OVERLAP_THRESHOLD = 0.5;
|
|
28
|
+
// Minimum distinctive shared tokens before we trust an overlap score. Filters
|
|
29
|
+
// out cases where two memories share only common English + a project name.
|
|
30
|
+
const CONFLICT_MIN_RARE_SHARED = 2;
|
|
31
|
+
// Polarity is detected on the first N words only. A stray "not" in the middle
|
|
32
|
+
// of a long memory shouldn't flip the whole thing negative.
|
|
33
|
+
const POLARITY_WINDOW_WORDS = 40;
|
|
34
|
+
const CONFLICT_STOPWORDS = new Set([
|
|
35
|
+
'the', 'a', 'an', 'is', 'was', 'are', 'were', 'be', 'been', 'being', 'to', 'of', 'in',
|
|
36
|
+
'for', 'on', 'with', 'at', 'by', 'from', 'it', 'this', 'that', 'and', 'or', 'but', 'so',
|
|
37
|
+
'if', 'as', 'we', 'i', 'you', 'they', 'he', 'she', 'my', 'our', 'your', 'its', 'his',
|
|
38
|
+
'her', 'their', 'up', 'out', 'just', 'also', 'then', 'than', 'some', 'all', 'any',
|
|
39
|
+
'each', 'very', 'too', 'do', 'did', 'does', 'has', 'had', 'have', 'will', 'would',
|
|
40
|
+
'could', 'should', 'may', 'might', 'can', 'shall', 'when', 'where', 'what', 'which',
|
|
41
|
+
'who', 'how', 'why', 'there', 'here', 'about', 'into', 'over', 'after', 'before',
|
|
42
|
+
'between', 'through', 'during', 'against', 'within', 'without', 'toward', 'upon',
|
|
43
|
+
'more', 'most', 'less', 'least', 'other', 'such', 'same', 'new', 'old', 'one', 'two',
|
|
44
|
+
]);
|
|
45
|
+
const REPLAY_COUNT_DEFAULT = 5;
|
|
46
|
+
/**
|
|
47
|
+
* Run a full consolidation pass.
|
|
48
|
+
*/
|
|
49
|
+
export async function consolidate(hippoRoot, options = {}) {
|
|
50
|
+
const now = options.now ?? new Date();
|
|
51
|
+
const dryRun = options.dryRun ?? false;
|
|
52
|
+
const result = {
|
|
53
|
+
decayed: 0,
|
|
54
|
+
removed: 0,
|
|
55
|
+
merged: 0,
|
|
56
|
+
semanticCreated: 0,
|
|
57
|
+
replayed: 0,
|
|
58
|
+
promotedTraces: 0,
|
|
59
|
+
extractionCandidates: 0,
|
|
60
|
+
extracted: 0,
|
|
61
|
+
dagCandidateClusters: 0,
|
|
62
|
+
dagSummariesCreated: 0,
|
|
63
|
+
dryRun,
|
|
64
|
+
details: [],
|
|
65
|
+
physicsSimulated: 0,
|
|
66
|
+
};
|
|
67
|
+
const all = loadAllEntries(hippoRoot);
|
|
68
|
+
// Load decay options from config + session context
|
|
69
|
+
const config = loadConfig(hippoRoot);
|
|
70
|
+
const sessionCtx = loadSessionDecayContext(hippoRoot);
|
|
71
|
+
const decayOpts = {
|
|
72
|
+
decayBasis: config.decayBasis,
|
|
73
|
+
avgSessionIntervalDays: sessionCtx.avgSessionIntervalDays,
|
|
74
|
+
sleepCount: sessionCtx.sleepCount,
|
|
75
|
+
};
|
|
76
|
+
// Collect all writes/deletes and batch them at the end
|
|
77
|
+
const pendingWrites = [];
|
|
78
|
+
const pendingDeletes = [];
|
|
79
|
+
// -------------------------------------------------------------------------
|
|
80
|
+
// 1. Decay pass
|
|
81
|
+
// -------------------------------------------------------------------------
|
|
82
|
+
const survivors = [];
|
|
83
|
+
for (const entry of all) {
|
|
84
|
+
const strength = calculateStrength(entry, now, decayOpts);
|
|
85
|
+
if (!entry.pinned && strength < DECAY_THRESHOLD) {
|
|
86
|
+
result.removed++;
|
|
87
|
+
result.details.push(` 🗑 removed ${entry.id} (strength ${strength.toFixed(4)} < ${DECAY_THRESHOLD})`);
|
|
88
|
+
if (!dryRun) {
|
|
89
|
+
pendingDeletes.push(entry.id);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Update the stored strength value and persist stale confidence when applicable.
|
|
94
|
+
const effectiveConfidence = resolveConfidence(entry, now);
|
|
95
|
+
const updated = {
|
|
96
|
+
...entry,
|
|
97
|
+
strength,
|
|
98
|
+
confidence: effectiveConfidence,
|
|
99
|
+
};
|
|
100
|
+
survivors.push(updated);
|
|
101
|
+
if (!dryRun && (strength !== entry.strength || effectiveConfidence !== entry.confidence)) {
|
|
102
|
+
pendingWrites.push(updated);
|
|
103
|
+
}
|
|
104
|
+
result.decayed++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// -------------------------------------------------------------------------
|
|
108
|
+
// 1.4. Auto-promote complete sessions to traces
|
|
109
|
+
// -------------------------------------------------------------------------
|
|
110
|
+
//
|
|
111
|
+
// For each session within the configured window that has a `session_complete`
|
|
112
|
+
// event and no existing trace (idempotency via the source_session_id column),
|
|
113
|
+
// render the action sequence as markdown and persist a Layer.Trace memory.
|
|
114
|
+
// Traces inherit decay, search, replay, and physics from the base MemoryEntry.
|
|
115
|
+
if (!dryRun && config.autoTraceCapture !== false) {
|
|
116
|
+
const windowDays = config.autoTraceWindowDays ?? 7;
|
|
117
|
+
const sinceMs = now.getTime() - windowDays * 24 * 60 * 60 * 1000;
|
|
118
|
+
const promotable = findPromotableSessions(hippoRoot, sinceMs);
|
|
119
|
+
for (const session of promotable) {
|
|
120
|
+
// Idempotency: skip if a trace for this session already exists.
|
|
121
|
+
if (traceExistsForSession(hippoRoot, session.session_id))
|
|
122
|
+
continue;
|
|
123
|
+
const events = listSessionEvents(hippoRoot, {
|
|
124
|
+
session_id: session.session_id,
|
|
125
|
+
limit: 1000,
|
|
126
|
+
});
|
|
127
|
+
const completeEvent = events.find((e) => e.event_type === 'session_complete');
|
|
128
|
+
if (!completeEvent)
|
|
129
|
+
continue; // defence-in-depth; findPromotableSessions filters already.
|
|
130
|
+
const outcomeRaw = completeEvent.content;
|
|
131
|
+
if (outcomeRaw !== 'success' && outcomeRaw !== 'failure' && outcomeRaw !== 'partial') {
|
|
132
|
+
// Malformed terminal event — skip rather than crash the whole sleep.
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const outcome = outcomeRaw;
|
|
136
|
+
const steps = events
|
|
137
|
+
.filter((e) => e.event_type !== 'session_complete')
|
|
138
|
+
.map((e) => ({ action: e.content, observation: '' }));
|
|
139
|
+
const summary = typeof completeEvent.metadata.summary === 'string'
|
|
140
|
+
? completeEvent.metadata.summary
|
|
141
|
+
: '(untitled)';
|
|
142
|
+
const trace = createMemory(renderTraceContent({ task: summary, steps, outcome }), {
|
|
143
|
+
layer: Layer.Trace,
|
|
144
|
+
trace_outcome: outcome,
|
|
145
|
+
source_session_id: session.session_id,
|
|
146
|
+
tags: ['auto-promoted'],
|
|
147
|
+
source: 'auto-promote',
|
|
148
|
+
});
|
|
149
|
+
pendingWrites.push(trace);
|
|
150
|
+
survivors.push(trace);
|
|
151
|
+
result.promotedTraces++;
|
|
152
|
+
result.details.push(` 🧬 promoted trace ${trace.id} from session ${session.session_id} (${outcome})`);
|
|
153
|
+
}
|
|
154
|
+
if (result.promotedTraces > 0) {
|
|
155
|
+
result.details.push(` 🧬 promoted ${result.promotedTraces} trace${result.promotedTraces === 1 ? '' : 's'} from completed session${result.promotedTraces === 1 ? '' : 's'}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// -------------------------------------------------------------------------
|
|
159
|
+
// 1.5. Replay pass — rehearse high-value survivors
|
|
160
|
+
// -------------------------------------------------------------------------
|
|
161
|
+
//
|
|
162
|
+
// Biologically-inspired counterpart to hippocampal replay during slow-wave
|
|
163
|
+
// sleep: sample N memories weighted by outcome + valence + under-rehearsal
|
|
164
|
+
// + idle time, then apply the same retrieval-strengthening `markRetrieved`
|
|
165
|
+
// applies to real queries. Distinct from decay (removal), physics (motion),
|
|
166
|
+
// and merge (compression) — this is the "rehearse the important stuff so
|
|
167
|
+
// it doesn't fade" pass.
|
|
168
|
+
{
|
|
169
|
+
const replayCount = config.replay?.count ?? REPLAY_COUNT_DEFAULT;
|
|
170
|
+
if (replayCount > 0 && survivors.length > 0) {
|
|
171
|
+
const seed = Math.floor(now.getTime() / 1000) & 0xffffffff;
|
|
172
|
+
const picked = sampleForReplay(survivors, replayCount, now, seed);
|
|
173
|
+
if (picked.length > 0) {
|
|
174
|
+
const rehearsed = markRetrieved(picked, now);
|
|
175
|
+
const rehearsedById = new Map(rehearsed.map((e) => [e.id, e]));
|
|
176
|
+
// Update survivors in place so downstream passes see rehearsed state.
|
|
177
|
+
for (let i = 0; i < survivors.length; i++) {
|
|
178
|
+
const replacement = rehearsedById.get(survivors[i].id);
|
|
179
|
+
if (replacement)
|
|
180
|
+
survivors[i] = replacement;
|
|
181
|
+
}
|
|
182
|
+
result.replayed = rehearsed.length;
|
|
183
|
+
result.details.push(` 💭 replayed ${rehearsed.length} memor${rehearsed.length === 1 ? 'y' : 'ies'}: ` +
|
|
184
|
+
rehearsed.map((e) => e.id).join(', '));
|
|
185
|
+
if (!dryRun) {
|
|
186
|
+
for (const r of rehearsed)
|
|
187
|
+
pendingWrites.push(r);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// -------------------------------------------------------------------------
|
|
193
|
+
// 1.6. Batch extraction — extract facts from episodic memories missing them
|
|
194
|
+
// -------------------------------------------------------------------------
|
|
195
|
+
const extractedFromIds = new Set(survivors.filter((e) => e.extracted_from).map((e) => e.extracted_from));
|
|
196
|
+
const extractionCandidates = survivors.filter((e) => e.layer === Layer.Episodic && !extractedFromIds.has(e.id));
|
|
197
|
+
result.extractionCandidates = extractionCandidates.length;
|
|
198
|
+
const apiKey = process.env.ANTHROPIC_API_KEY ?? '';
|
|
199
|
+
if (apiKey && extractionCandidates.length > 0 && !dryRun) {
|
|
200
|
+
const { extractFacts, storeExtractedFacts } = await import('./extract.js');
|
|
201
|
+
const batchLimit = 20;
|
|
202
|
+
let extractedCount = 0;
|
|
203
|
+
for (const candidate of extractionCandidates.slice(0, batchLimit)) {
|
|
204
|
+
try {
|
|
205
|
+
const facts = await extractFacts(candidate.content, {
|
|
206
|
+
apiKey,
|
|
207
|
+
model: config.extraction.model,
|
|
208
|
+
});
|
|
209
|
+
if (facts.length > 0) {
|
|
210
|
+
storeExtractedFacts(hippoRoot, candidate, facts);
|
|
211
|
+
extractedCount += facts.length;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Best-effort — continue with next candidate
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
result.extracted = extractedCount;
|
|
219
|
+
}
|
|
220
|
+
// -------------------------------------------------------------------------
|
|
221
|
+
// 1.7. DAG summarization — cluster extracted facts and generate summaries
|
|
222
|
+
// -------------------------------------------------------------------------
|
|
223
|
+
const extractedFacts = survivors.filter((e) => e.tags.includes('extracted') && e.dag_level === 1);
|
|
224
|
+
if (apiKey && extractedFacts.length >= 3 && !dryRun) {
|
|
225
|
+
try {
|
|
226
|
+
const { buildDag } = await import('./dag.js');
|
|
227
|
+
const dagResult = await buildDag(hippoRoot, extractedFacts, {
|
|
228
|
+
apiKey,
|
|
229
|
+
model: config.extraction.model,
|
|
230
|
+
});
|
|
231
|
+
result.dagCandidateClusters = dagResult.candidateClusters;
|
|
232
|
+
result.dagSummariesCreated = dagResult.summariesCreated;
|
|
233
|
+
if (dagResult.summariesCreated > 0) {
|
|
234
|
+
result.details.push(` 🌳 DAG: ${dagResult.summariesCreated} summaries created, ${dagResult.factsLinked} facts linked`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
// Best-effort
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// -------------------------------------------------------------------------
|
|
242
|
+
// 2. Physics simulation pass
|
|
243
|
+
// -------------------------------------------------------------------------
|
|
244
|
+
if (!dryRun) {
|
|
245
|
+
try {
|
|
246
|
+
const physicsEnabled = config.physics.enabled === true
|
|
247
|
+
|| (config.physics.enabled === 'auto');
|
|
248
|
+
if (physicsEnabled) {
|
|
249
|
+
const db = openHippoDb(hippoRoot);
|
|
250
|
+
try {
|
|
251
|
+
const physicsMap = loadPhysicsState(db);
|
|
252
|
+
const particles = Array.from(physicsMap.values());
|
|
253
|
+
if (particles.length > 0) {
|
|
254
|
+
// Build entry lookup for property refresh
|
|
255
|
+
const entryMap = new Map(survivors.map(e => [e.id, e]));
|
|
256
|
+
refreshParticleProperties(particles, entryMap, now);
|
|
257
|
+
// Build conflict pairs from survivors
|
|
258
|
+
const conflictPairs = new Map();
|
|
259
|
+
for (const entry of survivors) {
|
|
260
|
+
if (entry.conflicts_with.length > 0) {
|
|
261
|
+
const set = conflictPairs.get(entry.id) ?? new Set();
|
|
262
|
+
for (const cid of entry.conflicts_with)
|
|
263
|
+
set.add(cid);
|
|
264
|
+
conflictPairs.set(entry.id, set);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Build half-life lookup
|
|
268
|
+
const halfLives = new Map();
|
|
269
|
+
for (const entry of survivors) {
|
|
270
|
+
halfLives.set(entry.id, entry.half_life_days);
|
|
271
|
+
}
|
|
272
|
+
const ctx = {
|
|
273
|
+
conflictPairs,
|
|
274
|
+
halfLives,
|
|
275
|
+
config: config.physics,
|
|
276
|
+
};
|
|
277
|
+
const stats = simulate(particles, ctx);
|
|
278
|
+
savePhysicsState(db, particles);
|
|
279
|
+
result.physicsSimulated = stats.particleCount;
|
|
280
|
+
result.details.push(` ⚛️ physics: ${stats.particleCount} particles, ` +
|
|
281
|
+
`avg vel ${stats.avgVelocityMagnitude.toFixed(4)}, ` +
|
|
282
|
+
`energy ${stats.energy.total.toFixed(4)}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
finally {
|
|
286
|
+
closeHippoDb(db);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
result.details.push(` ⚠️ physics simulation skipped: ${error instanceof Error ? error.message : 'unknown error'}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// -------------------------------------------------------------------------
|
|
295
|
+
// 3. Merge pass - episodic entries only
|
|
296
|
+
// -------------------------------------------------------------------------
|
|
297
|
+
const mergeCandidates = survivors.filter((e) => e.layer === Layer.Episodic && !e.tags.includes('extracted'));
|
|
298
|
+
const used = new Set();
|
|
299
|
+
for (let i = 0; i < mergeCandidates.length; i++) {
|
|
300
|
+
if (used.has(mergeCandidates[i].id))
|
|
301
|
+
continue;
|
|
302
|
+
const cluster = [mergeCandidates[i]];
|
|
303
|
+
for (let j = i + 1; j < mergeCandidates.length; j++) {
|
|
304
|
+
if (used.has(mergeCandidates[j].id))
|
|
305
|
+
continue;
|
|
306
|
+
const overlap = textOverlap(mergeCandidates[i].content, mergeCandidates[j].content);
|
|
307
|
+
if (overlap >= MERGE_OVERLAP_THRESHOLD) {
|
|
308
|
+
cluster.push(mergeCandidates[j]);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (cluster.length < MERGE_MIN_CLUSTER)
|
|
312
|
+
continue;
|
|
313
|
+
// Mark cluster members as used
|
|
314
|
+
for (const e of cluster)
|
|
315
|
+
used.add(e.id);
|
|
316
|
+
result.merged += cluster.length;
|
|
317
|
+
// Create a semantic summary
|
|
318
|
+
const mergedContent = mergeContents(cluster);
|
|
319
|
+
const allTags = Array.from(new Set(cluster.flatMap((e) => e.tags)));
|
|
320
|
+
const maxValence = pickStrongestValence(cluster);
|
|
321
|
+
result.details.push(` 🔀 merged ${cluster.length} episodic entries into semantic: "${mergedContent.slice(0, 60)}..."`);
|
|
322
|
+
if (!dryRun) {
|
|
323
|
+
const semantic = createMemory(mergedContent, {
|
|
324
|
+
layer: Layer.Semantic,
|
|
325
|
+
tags: allTags,
|
|
326
|
+
emotional_valence: maxValence,
|
|
327
|
+
schema_fit: 0.7,
|
|
328
|
+
source: 'consolidation',
|
|
329
|
+
confidence: 'inferred',
|
|
330
|
+
});
|
|
331
|
+
pendingWrites.push(semantic);
|
|
332
|
+
result.semanticCreated++;
|
|
333
|
+
// Reduce strength of source episodics (they've been compressed into neocortex)
|
|
334
|
+
for (const e of cluster) {
|
|
335
|
+
const weakened = { ...e, strength: e.strength * 0.3 };
|
|
336
|
+
pendingWrites.push(weakened);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// Flush all writes/deletes in a single transaction
|
|
341
|
+
if (!dryRun) {
|
|
342
|
+
batchWriteAndDelete(hippoRoot, pendingWrites, pendingDeletes);
|
|
343
|
+
}
|
|
344
|
+
// -------------------------------------------------------------------------
|
|
345
|
+
// 4. Log run
|
|
346
|
+
// -------------------------------------------------------------------------
|
|
347
|
+
if (!dryRun) {
|
|
348
|
+
const detectedConflicts = detectConflicts(survivors, now, decayOpts);
|
|
349
|
+
replaceDetectedConflicts(hippoRoot, detectedConflicts, now.toISOString());
|
|
350
|
+
if (detectedConflicts.length > 0) {
|
|
351
|
+
result.details.push(` ⚠️ detected ${detectedConflicts.length} memory conflict${detectedConflicts.length === 1 ? '' : 's'}`);
|
|
352
|
+
}
|
|
353
|
+
appendConsolidationRun(hippoRoot, {
|
|
354
|
+
timestamp: now.toISOString(),
|
|
355
|
+
decayed: result.decayed,
|
|
356
|
+
merged: result.merged,
|
|
357
|
+
removed: result.removed,
|
|
358
|
+
});
|
|
359
|
+
incrementSleepCount(hippoRoot);
|
|
360
|
+
}
|
|
361
|
+
return result;
|
|
362
|
+
}
|
|
363
|
+
// ---------------------------------------------------------------------------
|
|
364
|
+
// Helpers
|
|
365
|
+
// ---------------------------------------------------------------------------
|
|
366
|
+
function mergeContents(entries) {
|
|
367
|
+
// Simple merge: take the longest entry as the base, prepend a summary note
|
|
368
|
+
const sorted = [...entries].sort((a, b) => b.content.length - a.content.length);
|
|
369
|
+
const base = sorted[0].content;
|
|
370
|
+
if (entries.length === 2) {
|
|
371
|
+
return `[Consolidated from ${entries.length} related memories]\n\n${base}`;
|
|
372
|
+
}
|
|
373
|
+
// For 3+ entries, create a bulleted summary
|
|
374
|
+
const bullets = entries.map((e) => `- ${e.content.split('\n')[0].slice(0, 120)}`).join('\n');
|
|
375
|
+
return `[Consolidated pattern from ${entries.length} related memories]\n\n${bullets}`;
|
|
376
|
+
}
|
|
377
|
+
function pickStrongestValence(entries) {
|
|
378
|
+
const order = ['critical', 'negative', 'positive', 'neutral'];
|
|
379
|
+
for (const v of order) {
|
|
380
|
+
if (entries.some((e) => e.emotional_valence === v))
|
|
381
|
+
return v;
|
|
382
|
+
}
|
|
383
|
+
return 'neutral';
|
|
384
|
+
}
|
|
385
|
+
function detectConflicts(entries, now, decayOpts = {}) {
|
|
386
|
+
const survivors = entries.filter((entry) => entry.layer !== Layer.Semantic && calculateStrength(entry, now, decayOpts) >= DECAY_THRESHOLD);
|
|
387
|
+
const detected = [];
|
|
388
|
+
for (let i = 0; i < survivors.length; i++) {
|
|
389
|
+
for (let j = i + 1; j < survivors.length; j++) {
|
|
390
|
+
// Traces are variants of each other, not contradictions. Two
|
|
391
|
+
// strategies for the same task can both be valid; conflict detection
|
|
392
|
+
// exists for stated-rule disagreement, not strategy diversity.
|
|
393
|
+
if (survivors[i].layer === Layer.Trace && survivors[j].layer === Layer.Trace)
|
|
394
|
+
continue;
|
|
395
|
+
if (survivors[i].superseded_by || survivors[j].superseded_by)
|
|
396
|
+
continue;
|
|
397
|
+
if (survivors[i].tags.includes('extracted') || survivors[j].tags.includes('extracted'))
|
|
398
|
+
continue;
|
|
399
|
+
const reasonAndScore = describeConflict(survivors[i], survivors[j]);
|
|
400
|
+
if (!reasonAndScore)
|
|
401
|
+
continue;
|
|
402
|
+
detected.push({
|
|
403
|
+
memory_a_id: survivors[i].id,
|
|
404
|
+
memory_b_id: survivors[j].id,
|
|
405
|
+
reason: reasonAndScore.reason,
|
|
406
|
+
score: reasonAndScore.score,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return detected;
|
|
411
|
+
}
|
|
412
|
+
function describeConflict(a, b) {
|
|
413
|
+
const aDistinct = distinctiveTokens(a.content);
|
|
414
|
+
const bDistinct = distinctiveTokens(b.content);
|
|
415
|
+
// Jaccard on stopword-stripped tokens. Defer the threshold check until we
|
|
416
|
+
// know whether an explicit polarity pair is present (lower bar for those).
|
|
417
|
+
const overlapScore = jaccardSets(aDistinct, bDistinct);
|
|
418
|
+
// Require at least N shared distinctive tokens so two short memories sharing
|
|
419
|
+
// only "the project name" don't register.
|
|
420
|
+
let shared = 0;
|
|
421
|
+
for (const t of aDistinct)
|
|
422
|
+
if (bDistinct.has(t))
|
|
423
|
+
shared++;
|
|
424
|
+
if (shared < CONFLICT_MIN_RARE_SHARED)
|
|
425
|
+
return null;
|
|
426
|
+
// Polarity is measured only in the first POLARITY_WINDOW_WORDS, so a stray
|
|
427
|
+
// negation deep in a prose memory doesn't flip the intent.
|
|
428
|
+
const polarityA = inferConflictPolarity(openingWindow(a.content));
|
|
429
|
+
const polarityB = inferConflictPolarity(openingWindow(b.content));
|
|
430
|
+
const conflictType = classifyConflictType(a.content, b.content, polarityA, polarityB);
|
|
431
|
+
if (!conflictType)
|
|
432
|
+
return null;
|
|
433
|
+
if (overlapScore < CONFLICT_OVERLAP_THRESHOLD)
|
|
434
|
+
return null;
|
|
435
|
+
return {
|
|
436
|
+
reason: conflictType,
|
|
437
|
+
score: overlapScore,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
function distinctiveTokens(text) {
|
|
441
|
+
return new Set(text
|
|
442
|
+
.toLowerCase()
|
|
443
|
+
.replace(/[^\w\s]/g, ' ')
|
|
444
|
+
.split(/\s+/)
|
|
445
|
+
.filter((t) => t.length > 2 && !CONFLICT_STOPWORDS.has(t)));
|
|
446
|
+
}
|
|
447
|
+
function jaccardSets(a, b) {
|
|
448
|
+
if (a.size === 0 && b.size === 0)
|
|
449
|
+
return 1;
|
|
450
|
+
if (a.size === 0 || b.size === 0)
|
|
451
|
+
return 0;
|
|
452
|
+
let inter = 0;
|
|
453
|
+
for (const t of a)
|
|
454
|
+
if (b.has(t))
|
|
455
|
+
inter++;
|
|
456
|
+
const union = a.size + b.size - inter;
|
|
457
|
+
return union === 0 ? 0 : inter / union;
|
|
458
|
+
}
|
|
459
|
+
function openingWindow(text) {
|
|
460
|
+
return text.split(/\s+/).slice(0, POLARITY_WINDOW_WORDS).join(' ');
|
|
461
|
+
}
|
|
462
|
+
function classifyConflictType(aText, bText, aPolarity, bPolarity) {
|
|
463
|
+
// Classifier scans only the opening window of each memory so " on " and
|
|
464
|
+
// " off " used as English prepositions deep in a long prose memory don't
|
|
465
|
+
// trigger an enabled/disabled flag. The opening window is where a rule or
|
|
466
|
+
// declaration is typically stated.
|
|
467
|
+
// Pad with spaces so space-delimited patterns match words at the start/end.
|
|
468
|
+
const a = ' ' + openingWindow(aText).toLowerCase() + ' ';
|
|
469
|
+
const b = ' ' + openingWindow(bText).toLowerCase() + ' ';
|
|
470
|
+
// Tightened tokens: require whole-word boundaries so " on " alone doesn't
|
|
471
|
+
// match "on/off". Pair only `enabled` ↔ `disabled` and explicit on/off in
|
|
472
|
+
// imperative context.
|
|
473
|
+
const enabledDisabled = (containsAny(a, [' enabled ', ' enable ']) && containsAny(b, [' disabled ', ' disable ']))
|
|
474
|
+
|| (containsAny(b, [' enabled ', ' enable ']) && containsAny(a, [' disabled ', ' disable ']));
|
|
475
|
+
if (enabledDisabled)
|
|
476
|
+
return 'enabled/disabled mismatch on overlapping statement';
|
|
477
|
+
const trueFalse = (containsAny(a, [' true ', ' true.', ' true,', ' yes ']) && containsAny(b, [' false ', ' false.', ' false,', ' no ']))
|
|
478
|
+
|| (containsAny(b, [' true ', ' true.', ' true,', ' yes ']) && containsAny(a, [' false ', ' false.', ' false,', ' no ']));
|
|
479
|
+
if (trueFalse)
|
|
480
|
+
return 'true/false mismatch on overlapping statement';
|
|
481
|
+
const alwaysNever = (containsAny(a, [' always ', ' must ']) && containsAny(b, [' never ', ' must not ']))
|
|
482
|
+
|| (containsAny(b, [' always ', ' must ']) && containsAny(a, [' never ', ' must not ']));
|
|
483
|
+
if (alwaysNever)
|
|
484
|
+
return 'always/never mismatch on overlapping statement';
|
|
485
|
+
if ((aPolarity === 'positive' && bPolarity === 'negative') || (aPolarity === 'negative' && bPolarity === 'positive')) {
|
|
486
|
+
return 'negation polarity mismatch on overlapping statement';
|
|
487
|
+
}
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
function inferConflictPolarity(text) {
|
|
491
|
+
const lowered = ` ${text.toLowerCase()} `;
|
|
492
|
+
const negativePatterns = [
|
|
493
|
+
' not ', ' never ', ' no ', " don't ", ' do not ', " doesn't ", ' does not ',
|
|
494
|
+
" can't ", ' cannot ', " shouldn't ", ' should not ', ' disabled ', ' disable ', ' off ',
|
|
495
|
+
' false ', ' missing ', ' broken ', ' failed ',
|
|
496
|
+
];
|
|
497
|
+
const positivePatterns = [
|
|
498
|
+
' enabled ', ' enable ', ' works ', ' working ', ' true ', ' available ', ' present ', ' on ',
|
|
499
|
+
' always ', ' must ',
|
|
500
|
+
];
|
|
501
|
+
if (containsAny(lowered, negativePatterns))
|
|
502
|
+
return 'negative';
|
|
503
|
+
if (containsAny(lowered, positivePatterns))
|
|
504
|
+
return 'positive';
|
|
505
|
+
return 'neutral';
|
|
506
|
+
}
|
|
507
|
+
function stripConflictPolarity(text) {
|
|
508
|
+
return text
|
|
509
|
+
.toLowerCase()
|
|
510
|
+
.replace(/\b(?:not|never|no|don['’]?t|do\s+not|doesn['’]?t|does\s+not|can['’]?t|cannot|shouldn['’]?t|should\s+not|enabled|enable|disabled|disable|on|off|true|false|always|must|must\s+not|works?|working|missing|broken|failed|available|present)\b/g, ' ')
|
|
511
|
+
.replace(/\s+/g, ' ')
|
|
512
|
+
.trim();
|
|
513
|
+
}
|
|
514
|
+
function containsAny(text, needles) {
|
|
515
|
+
return needles.some((needle) => text.includes(needle));
|
|
516
|
+
}
|
|
517
|
+
//# sourceMappingURL=consolidate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidate.js","sourceRoot":"","sources":["../../src/consolidate.ts"],"names":[],"mappings":"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"}
|
package/dist/src/dag.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createMemory, Layer } from './memory.js';
|
|
2
|
+
import { writeEntry } from './store.js';
|
|
3
|
+
export function clusterFacts(facts) {
|
|
4
|
+
if (facts.length === 0)
|
|
5
|
+
return [];
|
|
6
|
+
const entityTags = facts.map((f) => f.tags.filter((t) => t.startsWith('speaker:') || t.startsWith('topic:')));
|
|
7
|
+
const assigned = new Set();
|
|
8
|
+
const clusters = [];
|
|
9
|
+
for (let i = 0; i < facts.length; i++) {
|
|
10
|
+
if (assigned.has(i))
|
|
11
|
+
continue;
|
|
12
|
+
const cluster = [i];
|
|
13
|
+
assigned.add(i);
|
|
14
|
+
for (let j = i + 1; j < facts.length; j++) {
|
|
15
|
+
if (assigned.has(j))
|
|
16
|
+
continue;
|
|
17
|
+
const shared = entityTags[i].filter((t) => entityTags[j].includes(t));
|
|
18
|
+
const union = new Set([...entityTags[i], ...entityTags[j]]);
|
|
19
|
+
const jaccard = union.size > 0 ? shared.length / union.size : 0;
|
|
20
|
+
if (jaccard >= 0.5) {
|
|
21
|
+
cluster.push(j);
|
|
22
|
+
assigned.add(j);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const members = cluster.map((idx) => facts[idx]);
|
|
26
|
+
const sharedTags = entityTags[cluster[0]].filter((t) => cluster.every((idx) => entityTags[idx].includes(t)));
|
|
27
|
+
const label = sharedTags
|
|
28
|
+
.map((t) => t.split(':')[1])
|
|
29
|
+
.join(': ') || members[0].content.slice(0, 40);
|
|
30
|
+
clusters.push({ label, members, entityTags: sharedTags });
|
|
31
|
+
}
|
|
32
|
+
return clusters;
|
|
33
|
+
}
|
|
34
|
+
const DAG_SUMMARY_PROMPT = `You are summarizing a cluster of facts about a specific topic/entity for a memory system.
|
|
35
|
+
|
|
36
|
+
Topic: {label}
|
|
37
|
+
Facts:
|
|
38
|
+
{facts}
|
|
39
|
+
|
|
40
|
+
Write a single concise paragraph (2-4 sentences) that captures all the key information from these facts. This summary will be used to quickly determine if this cluster is relevant to a future query, so include specific names, dates, numbers, and key details. Output ONLY the summary paragraph, no preamble.`;
|
|
41
|
+
export async function generateDagSummary(label, factContents, opts) {
|
|
42
|
+
const model = opts.model ?? 'claude-sonnet-4-6';
|
|
43
|
+
const fetchFn = opts.fetcher ?? fetch;
|
|
44
|
+
const factsBlock = factContents.map((f, i) => `${i + 1}. ${f}`).join('\n');
|
|
45
|
+
const prompt = DAG_SUMMARY_PROMPT
|
|
46
|
+
.replace('{label}', label)
|
|
47
|
+
.replace('{facts}', factsBlock);
|
|
48
|
+
let res;
|
|
49
|
+
try {
|
|
50
|
+
res = await fetchFn('https://api.anthropic.com/v1/messages', {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: {
|
|
53
|
+
'content-type': 'application/json',
|
|
54
|
+
'x-api-key': opts.apiKey,
|
|
55
|
+
'anthropic-version': '2023-06-01',
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
model,
|
|
59
|
+
max_tokens: 400,
|
|
60
|
+
messages: [{ role: 'user', content: prompt }],
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
if (!res.ok)
|
|
68
|
+
return null;
|
|
69
|
+
try {
|
|
70
|
+
const data = (await res.json());
|
|
71
|
+
const text = data.content?.[0]?.text?.trim() ?? '';
|
|
72
|
+
return text.length >= 20 ? text : null;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export async function buildDag(hippoRoot, facts, opts) {
|
|
79
|
+
const result = { candidateClusters: 0, summariesCreated: 0, factsLinked: 0 };
|
|
80
|
+
const unparented = facts.filter((f) => f.dag_level === 1 && !f.dag_parent_id && f.tags.includes('extracted'));
|
|
81
|
+
const clusters = clusterFacts(unparented);
|
|
82
|
+
const eligibleClusters = clusters.filter((c) => c.members.length >= 3);
|
|
83
|
+
result.candidateClusters = eligibleClusters.length;
|
|
84
|
+
for (const cluster of eligibleClusters) {
|
|
85
|
+
const summary = await generateDagSummary(cluster.label, cluster.members.map((m) => m.content), opts);
|
|
86
|
+
if (!summary)
|
|
87
|
+
continue;
|
|
88
|
+
const summaryEntry = createMemory(summary, {
|
|
89
|
+
layer: Layer.Semantic,
|
|
90
|
+
tags: [...cluster.entityTags, 'dag-summary'],
|
|
91
|
+
confidence: 'inferred',
|
|
92
|
+
dag_level: 2,
|
|
93
|
+
});
|
|
94
|
+
writeEntry(hippoRoot, summaryEntry);
|
|
95
|
+
result.summariesCreated++;
|
|
96
|
+
for (const member of cluster.members) {
|
|
97
|
+
const updated = { ...member, dag_parent_id: summaryEntry.id };
|
|
98
|
+
writeEntry(hippoRoot, updated);
|
|
99
|
+
result.factsLinked++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=dag.js.map
|