@theihtisham/agent-shadow-brain 6.0.0 → 6.0.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.
Files changed (144) hide show
  1. package/README.md +107 -7
  2. package/dist/brain/brain-3d.d.ts +79 -0
  3. package/dist/brain/brain-3d.d.ts.map +1 -0
  4. package/dist/brain/brain-3d.js +468 -0
  5. package/dist/brain/brain-3d.js.map +1 -0
  6. package/dist/brain/brain-active-learner.d.ts +74 -0
  7. package/dist/brain/brain-active-learner.d.ts.map +1 -0
  8. package/dist/brain/brain-active-learner.js +425 -0
  9. package/dist/brain/brain-active-learner.js.map +1 -0
  10. package/dist/brain/brain-ascii.d.ts +32 -0
  11. package/dist/brain/brain-ascii.d.ts.map +1 -0
  12. package/dist/brain/brain-ascii.js +402 -0
  13. package/dist/brain/brain-ascii.js.map +1 -0
  14. package/dist/brain/brain-cinema.d.ts +45 -0
  15. package/dist/brain/brain-cinema.d.ts.map +1 -0
  16. package/dist/brain/brain-cinema.js +393 -0
  17. package/dist/brain/brain-cinema.js.map +1 -0
  18. package/dist/brain/brain-coach.d.ts +45 -0
  19. package/dist/brain/brain-coach.d.ts.map +1 -0
  20. package/dist/brain/brain-coach.js +383 -0
  21. package/dist/brain/brain-coach.js.map +1 -0
  22. package/dist/brain/brain-consolidator.d.ts +56 -0
  23. package/dist/brain/brain-consolidator.d.ts.map +1 -0
  24. package/dist/brain/brain-consolidator.js +386 -0
  25. package/dist/brain/brain-consolidator.js.map +1 -0
  26. package/dist/brain/brain-contradictions.d.ts +57 -0
  27. package/dist/brain/brain-contradictions.d.ts.map +1 -0
  28. package/dist/brain/brain-contradictions.js +443 -0
  29. package/dist/brain/brain-contradictions.js.map +1 -0
  30. package/dist/brain/brain-diff.d.ts +61 -0
  31. package/dist/brain/brain-diff.d.ts.map +1 -0
  32. package/dist/brain/brain-diff.js +439 -0
  33. package/dist/brain/brain-diff.js.map +1 -0
  34. package/dist/brain/brain-dna.d.ts +59 -0
  35. package/dist/brain/brain-dna.d.ts.map +1 -0
  36. package/dist/brain/brain-dna.js +336 -0
  37. package/dist/brain/brain-dna.js.map +1 -0
  38. package/dist/brain/brain-doppelganger.d.ts +32 -0
  39. package/dist/brain/brain-doppelganger.d.ts.map +1 -0
  40. package/dist/brain/brain-doppelganger.js +417 -0
  41. package/dist/brain/brain-doppelganger.js.map +1 -0
  42. package/dist/brain/brain-graph-walker.d.ts +54 -0
  43. package/dist/brain/brain-graph-walker.d.ts.map +1 -0
  44. package/dist/brain/brain-graph-walker.js +412 -0
  45. package/dist/brain/brain-graph-walker.js.map +1 -0
  46. package/dist/brain/brain-holiday-card.d.ts +50 -0
  47. package/dist/brain/brain-holiday-card.d.ts.map +1 -0
  48. package/dist/brain/brain-holiday-card.js +432 -0
  49. package/dist/brain/brain-holiday-card.js.map +1 -0
  50. package/dist/brain/brain-memes.d.ts +44 -0
  51. package/dist/brain/brain-memes.d.ts.map +1 -0
  52. package/dist/brain/brain-memes.js +438 -0
  53. package/dist/brain/brain-memes.js.map +1 -0
  54. package/dist/brain/brain-memory-tiers.d.ts +67 -0
  55. package/dist/brain/brain-memory-tiers.d.ts.map +1 -0
  56. package/dist/brain/brain-memory-tiers.js +292 -0
  57. package/dist/brain/brain-memory-tiers.js.map +1 -0
  58. package/dist/brain/brain-notebook.d.ts +68 -0
  59. package/dist/brain/brain-notebook.d.ts.map +1 -0
  60. package/dist/brain/brain-notebook.js +379 -0
  61. package/dist/brain/brain-notebook.js.map +1 -0
  62. package/dist/brain/brain-quantize.d.ts +62 -0
  63. package/dist/brain/brain-quantize.d.ts.map +1 -0
  64. package/dist/brain/brain-quantize.js +346 -0
  65. package/dist/brain/brain-quantize.js.map +1 -0
  66. package/dist/brain/brain-query-expander.d.ts +31 -0
  67. package/dist/brain/brain-query-expander.d.ts.map +1 -0
  68. package/dist/brain/brain-query-expander.js +417 -0
  69. package/dist/brain/brain-query-expander.js.map +1 -0
  70. package/dist/brain/brain-quest.d.ts +58 -0
  71. package/dist/brain/brain-quest.d.ts.map +1 -0
  72. package/dist/brain/brain-quest.js +541 -0
  73. package/dist/brain/brain-quest.js.map +1 -0
  74. package/dist/brain/brain-recall-cache.d.ts +73 -0
  75. package/dist/brain/brain-recall-cache.d.ts.map +1 -0
  76. package/dist/brain/brain-recall-cache.js +444 -0
  77. package/dist/brain/brain-recall-cache.js.map +1 -0
  78. package/dist/brain/brain-reflex.d.ts +55 -0
  79. package/dist/brain/brain-reflex.d.ts.map +1 -0
  80. package/dist/brain/brain-reflex.js +364 -0
  81. package/dist/brain/brain-reflex.js.map +1 -0
  82. package/dist/brain/brain-replay.d.ts +74 -0
  83. package/dist/brain/brain-replay.d.ts.map +1 -0
  84. package/dist/brain/brain-replay.js +336 -0
  85. package/dist/brain/brain-replay.js.map +1 -0
  86. package/dist/brain/brain-rerank.d.ts +39 -0
  87. package/dist/brain/brain-rerank.d.ts.map +1 -0
  88. package/dist/brain/brain-rerank.js +216 -0
  89. package/dist/brain/brain-rerank.js.map +1 -0
  90. package/dist/brain/brain-roast.d.ts +44 -0
  91. package/dist/brain/brain-roast.d.ts.map +1 -0
  92. package/dist/brain/brain-roast.js +566 -0
  93. package/dist/brain/brain-roast.js.map +1 -0
  94. package/dist/brain/brain-sonification.d.ts +57 -0
  95. package/dist/brain/brain-sonification.d.ts.map +1 -0
  96. package/dist/brain/brain-sonification.js +286 -0
  97. package/dist/brain/brain-sonification.js.map +1 -0
  98. package/dist/brain/brain-tarot.d.ts +49 -0
  99. package/dist/brain/brain-tarot.d.ts.map +1 -0
  100. package/dist/brain/brain-tarot.js +634 -0
  101. package/dist/brain/brain-tarot.js.map +1 -0
  102. package/dist/brain/brain-time-capsule.d.ts +80 -0
  103. package/dist/brain/brain-time-capsule.d.ts.map +1 -0
  104. package/dist/brain/brain-time-capsule.js +289 -0
  105. package/dist/brain/brain-time-capsule.js.map +1 -0
  106. package/dist/brain/brain-trophies.d.ts +60 -0
  107. package/dist/brain/brain-trophies.d.ts.map +1 -0
  108. package/dist/brain/brain-trophies.js +431 -0
  109. package/dist/brain/brain-trophies.js.map +1 -0
  110. package/dist/brain/brain-working-memory.d.ts +78 -0
  111. package/dist/brain/brain-working-memory.d.ts.map +1 -0
  112. package/dist/brain/brain-working-memory.js +367 -0
  113. package/dist/brain/brain-working-memory.js.map +1 -0
  114. package/dist/brain/confidence-gate.d.ts +69 -0
  115. package/dist/brain/confidence-gate.d.ts.map +1 -0
  116. package/dist/brain/confidence-gate.js +244 -0
  117. package/dist/brain/confidence-gate.js.map +1 -0
  118. package/dist/brain/constitution.d.ts +59 -0
  119. package/dist/brain/constitution.d.ts.map +1 -0
  120. package/dist/brain/constitution.js +315 -0
  121. package/dist/brain/constitution.js.map +1 -0
  122. package/dist/brain/embeddings-v2.d.ts +58 -0
  123. package/dist/brain/embeddings-v2.d.ts.map +1 -0
  124. package/dist/brain/embeddings-v2.js +344 -0
  125. package/dist/brain/embeddings-v2.js.map +1 -0
  126. package/dist/brain/hive-voice.d.ts +71 -0
  127. package/dist/brain/hive-voice.d.ts.map +1 -0
  128. package/dist/brain/hive-voice.js +352 -0
  129. package/dist/brain/hive-voice.js.map +1 -0
  130. package/dist/brain/markdown-export.d.ts +48 -0
  131. package/dist/brain/markdown-export.d.ts.map +1 -0
  132. package/dist/brain/markdown-export.js +382 -0
  133. package/dist/brain/markdown-export.js.map +1 -0
  134. package/dist/brain/multimodal-vision.d.ts +38 -0
  135. package/dist/brain/multimodal-vision.d.ts.map +1 -0
  136. package/dist/brain/multimodal-vision.js +257 -0
  137. package/dist/brain/multimodal-vision.js.map +1 -0
  138. package/dist/brain/otel-lite.d.ts +71 -0
  139. package/dist/brain/otel-lite.d.ts.map +1 -0
  140. package/dist/brain/otel-lite.js +232 -0
  141. package/dist/brain/otel-lite.js.map +1 -0
  142. package/dist/cli.js +881 -2
  143. package/dist/cli.js.map +1 -1
  144. package/package.json +2 -2
@@ -0,0 +1,336 @@
1
+ // src/brain/brain-replay.ts — Brain Replay (viral feature)
2
+ // v6.0.2
3
+ //
4
+ // The "AlphaGo replay" for codebases. A scrubbable, day-zero timeline of every
5
+ // brain event in a project. Records to a per-project JSONL log, computes
6
+ // snapshot frames at intervals, and exports a Twitter-ready SVG timeline.
7
+ //
8
+ // Storage: ~/.shadow-brain/replay/<project_hash>.jsonl (append-only events)
9
+ // ~/.shadow-brain/replay/<project_hash>.snap.json (compact snapshots)
10
+ //
11
+ // Independent of causal-chains.ts and brain-garden.ts. Reads global brain for
12
+ // entity state when computing frames; works gracefully on empty input.
13
+ import * as fs from 'fs';
14
+ import * as path from 'path';
15
+ import * as os from 'os';
16
+ import * as crypto from 'crypto';
17
+ import { getGlobalBrain } from './global-brain.js';
18
+ const REPLAY_DIR = path.join(os.homedir(), '.shadow-brain', 'replay');
19
+ const FRAME_EVERY_EVENTS = 100;
20
+ const FRAME_EVERY_MS = 60 * 60 * 1000; // 1 hour
21
+ const COMPRESS_THRESHOLD = 5000;
22
+ // ── Class ────────────────────────────────────────────────────────────────────
23
+ export class BrainReplay {
24
+ constructor(brain) {
25
+ this.brain = brain ?? getGlobalBrain();
26
+ try {
27
+ fs.mkdirSync(REPLAY_DIR, { recursive: true });
28
+ }
29
+ catch { /* ignore */ }
30
+ }
31
+ /** Append an event to the per-project log. */
32
+ record(event) {
33
+ const project = event.project ?? 'default';
34
+ const full = {
35
+ type: event.type,
36
+ payload: event.payload,
37
+ ts: event.ts ?? Date.now(),
38
+ project,
39
+ agent: event.agent,
40
+ };
41
+ try {
42
+ const file = this.fileFor(project);
43
+ fs.appendFileSync(file, JSON.stringify(full) + '\n');
44
+ }
45
+ catch { /* persistence non-fatal */ }
46
+ }
47
+ /** Read all events for a project as a timeline of frames (downsampled). */
48
+ getTimeline(project, opts = {}) {
49
+ const events = this.readEvents(project, opts);
50
+ if (!events.length)
51
+ return [];
52
+ const frames = [];
53
+ const seen = new Set();
54
+ let lastFrameTs = events[0].ts;
55
+ let lastFrameIdx = 0;
56
+ for (let i = 0; i < events.length; i++) {
57
+ const ev = events[i];
58
+ const sinceLast = ev.ts - lastFrameTs;
59
+ const eventsSinceLast = i - lastFrameIdx;
60
+ const shouldFrame = i === events.length - 1 ||
61
+ eventsSinceLast >= FRAME_EVERY_EVENTS ||
62
+ sinceLast >= FRAME_EVERY_MS;
63
+ if (shouldFrame) {
64
+ frames.push(this.buildFrame(events.slice(0, i + 1), seen, frames[frames.length - 1]));
65
+ lastFrameTs = ev.ts;
66
+ lastFrameIdx = i;
67
+ }
68
+ }
69
+ return frames;
70
+ }
71
+ /** Return the brain state as it would have appeared at exactly `ts`. */
72
+ frameAt(project, ts) {
73
+ const events = this.readEvents(project, { to: ts });
74
+ if (!events.length)
75
+ return this.emptyFrame(ts);
76
+ const seen = new Set();
77
+ return this.buildFrame(events, seen);
78
+ }
79
+ /** Compact old events into snapshots + diff chains; keeps file size bounded. */
80
+ compress(project) {
81
+ const file = this.fileFor(project);
82
+ if (!fs.existsSync(file))
83
+ return { kept: 0, archived: 0 };
84
+ const events = this.readEvents(project);
85
+ if (events.length < COMPRESS_THRESHOLD)
86
+ return { kept: events.length, archived: 0 };
87
+ // Keep most recent half raw; collapse older half into snapshot frames.
88
+ const cutoff = Math.floor(events.length / 2);
89
+ const older = events.slice(0, cutoff);
90
+ const newer = events.slice(cutoff);
91
+ const seen = new Set();
92
+ const snapshots = [];
93
+ for (let i = FRAME_EVERY_EVENTS; i <= older.length; i += FRAME_EVERY_EVENTS) {
94
+ snapshots.push(this.buildFrame(older.slice(0, i), seen, snapshots[snapshots.length - 1]));
95
+ }
96
+ // Write snapshots sidecar + rewrite jsonl with only newer events.
97
+ try {
98
+ const snapFile = path.join(REPLAY_DIR, this.projectHash(project) + '.snap.json');
99
+ fs.writeFileSync(snapFile, JSON.stringify({ schemaVersion: 1, snapshots }, null, 2));
100
+ const tmp = file + '.tmp';
101
+ fs.writeFileSync(tmp, newer.map(e => JSON.stringify(e)).join('\n') + '\n');
102
+ fs.renameSync(tmp, file);
103
+ }
104
+ catch { /* non-fatal */ }
105
+ return { kept: newer.length, archived: older.length };
106
+ }
107
+ /** Export as JSONL string, CSV string, or SVG Buffer. */
108
+ export(project, format) {
109
+ const events = this.readEvents(project);
110
+ if (format === 'jsonl') {
111
+ return events.map(e => JSON.stringify(e)).join('\n');
112
+ }
113
+ if (format === 'csv') {
114
+ const rows = ['ts,iso,type,agent,project'];
115
+ for (const e of events) {
116
+ const iso = new Date(e.ts).toISOString();
117
+ rows.push(`${e.ts},${iso},${e.type},${e.agent ?? ''},${e.project}`);
118
+ }
119
+ return rows.join('\n');
120
+ }
121
+ return Buffer.from(this.renderSvg(project, events), 'utf-8');
122
+ }
123
+ /** Get the raw event list (used by Brain DNA + tests). */
124
+ listEvents(project, opts = {}) {
125
+ return this.readEvents(project, opts);
126
+ }
127
+ // ── Internals ──────────────────────────────────────────────────────────────
128
+ fileFor(project) {
129
+ return path.join(REPLAY_DIR, this.projectHash(project) + '.jsonl');
130
+ }
131
+ projectHash(project) {
132
+ return crypto.createHash('sha1').update(path.resolve(project)).digest('hex').slice(0, 16);
133
+ }
134
+ readEvents(project, opts = {}) {
135
+ const file = this.fileFor(project);
136
+ if (!fs.existsSync(file))
137
+ return [];
138
+ const out = [];
139
+ try {
140
+ const raw = fs.readFileSync(file, 'utf-8');
141
+ for (const line of raw.split('\n')) {
142
+ if (!line.trim())
143
+ continue;
144
+ try {
145
+ const ev = JSON.parse(line);
146
+ if (opts.from && ev.ts < opts.from)
147
+ continue;
148
+ if (opts.to && ev.ts > opts.to)
149
+ continue;
150
+ if (opts.types && !opts.types.includes(ev.type))
151
+ continue;
152
+ out.push(ev);
153
+ }
154
+ catch { /* skip bad line */ }
155
+ }
156
+ }
157
+ catch { /* missing file */ }
158
+ out.sort((a, b) => a.ts - b.ts);
159
+ return out;
160
+ }
161
+ buildFrame(events, seen, prev) {
162
+ const ts = events[events.length - 1].ts;
163
+ const entityCounts = new Map();
164
+ let memoryCount = 0;
165
+ let modified = 0;
166
+ for (const ev of events) {
167
+ const key = this.entityKeyOf(ev);
168
+ if (key) {
169
+ if (seen.has(key))
170
+ modified++;
171
+ else
172
+ seen.add(key);
173
+ entityCounts.set(key, (entityCounts.get(key) ?? 0) + 1);
174
+ }
175
+ if (ev.type === 'memory.write' || ev.type === 'brain.remember')
176
+ memoryCount++;
177
+ }
178
+ const topEntities = Array.from(entityCounts.entries())
179
+ .sort((a, b) => b[1] - a[1])
180
+ .slice(0, 5)
181
+ .map(([k]) => k);
182
+ const prevCount = prev?.eventCount ?? 0;
183
+ const prevEntities = prev?.entityCount ?? 0;
184
+ const added = Math.max(0, seen.size - prevEntities);
185
+ const decayed = events.filter(e => e.type === 'memory.decay' || e.type === 'forget').length;
186
+ return {
187
+ ts,
188
+ eventCount: events.length,
189
+ memoryCount,
190
+ entityCount: seen.size,
191
+ topEntities,
192
+ deltaFromPrevious: { added, modified: Math.max(0, modified - (prev?.eventCount ?? 0)), decayed },
193
+ healthScore: this.estimateHealth(events.length - prevCount, decayed),
194
+ };
195
+ }
196
+ entityKeyOf(ev) {
197
+ const p = ev.payload;
198
+ if (!p || typeof p !== 'object')
199
+ return null;
200
+ return p.entity || p.id || p.name || null;
201
+ }
202
+ estimateHealth(eventsInFrame, decayed) {
203
+ if (eventsInFrame === 0)
204
+ return 0.5;
205
+ const decayRatio = decayed / eventsInFrame;
206
+ return Math.max(0, Math.min(1, 1 - decayRatio * 0.5));
207
+ }
208
+ emptyFrame(ts) {
209
+ return { ts, eventCount: 0, memoryCount: 0, entityCount: 0, topEntities: [],
210
+ deltaFromPrevious: { added: 0, modified: 0, decayed: 0 }, healthScore: 0.5 };
211
+ }
212
+ // ── SVG renderer (Twitter-ready marketing artifact) ─────────────────────────
213
+ renderSvg(project, events) {
214
+ const W = 1200, H = 300, PAD = 40;
215
+ const innerW = W - PAD * 2;
216
+ const innerH = H - PAD * 2;
217
+ const projName = path.basename(path.resolve(project));
218
+ if (!events.length)
219
+ return this.emptySvg(W, H, projName);
220
+ const t0 = events[0].ts;
221
+ const t1 = events[events.length - 1].ts;
222
+ const span = Math.max(1, t1 - t0);
223
+ // Histogram of event density across 80 buckets
224
+ const BUCKETS = 80;
225
+ const buckets = new Array(BUCKETS).fill(0);
226
+ for (const ev of events) {
227
+ const b = Math.min(BUCKETS - 1, Math.floor(((ev.ts - t0) / span) * BUCKETS));
228
+ buckets[b]++;
229
+ }
230
+ const peak = Math.max(1, ...buckets);
231
+ // Color map per event type
232
+ const typeColor = (t) => {
233
+ if (t.startsWith('memory') || t.includes('remember'))
234
+ return '#00ffd5';
235
+ if (t.includes('decay') || t.includes('forget'))
236
+ return '#ff5577';
237
+ if (t.includes('agent') || t.includes('handoff'))
238
+ return '#ffb84d';
239
+ if (t.includes('decision') || t.includes('adr'))
240
+ return '#a78bfa';
241
+ if (t.includes('collision') || t.includes('error'))
242
+ return '#ff3860';
243
+ return '#7dd3fc';
244
+ };
245
+ // Milestone markers: first memory, 100th entity, first collision, halfway, last
246
+ const milestones = this.findMilestones(events);
247
+ const bars = [];
248
+ const barW = innerW / BUCKETS;
249
+ for (let i = 0; i < BUCKETS; i++) {
250
+ const h = (buckets[i] / peak) * (innerH - 40);
251
+ const x = PAD + i * barW;
252
+ const y = H - PAD - h;
253
+ bars.push(`<rect x="${x.toFixed(1)}" y="${y.toFixed(1)}" width="${(barW - 1).toFixed(1)}" height="${h.toFixed(1)}" fill="url(#barGrad)" rx="1"/>`);
254
+ }
255
+ const dots = [];
256
+ const maxDots = 400;
257
+ const stride = Math.max(1, Math.ceil(events.length / maxDots));
258
+ for (let i = 0; i < events.length; i += stride) {
259
+ const ev = events[i];
260
+ const x = PAD + ((ev.ts - t0) / span) * innerW;
261
+ const y = H - PAD - 4;
262
+ dots.push(`<circle cx="${x.toFixed(1)}" cy="${y}" r="2" fill="${typeColor(ev.type)}" opacity="0.85"/>`);
263
+ }
264
+ const marks = [];
265
+ for (const m of milestones) {
266
+ const x = PAD + ((m.ts - t0) / span) * innerW;
267
+ marks.push(`<line x1="${x.toFixed(1)}" y1="${PAD + 8}" x2="${x.toFixed(1)}" y2="${H - PAD}" stroke="#ffffff" stroke-width="0.5" stroke-dasharray="3,3" opacity="0.4"/>`);
268
+ marks.push(`<text x="${x.toFixed(1)}" y="${PAD + 4}" fill="#ffffff" font-size="9" font-family="ui-monospace,monospace" text-anchor="middle" opacity="0.7">${esc(m.label)}</text>`);
269
+ }
270
+ const days = Math.max(1, Math.round((t1 - t0) / (24 * 60 * 60 * 1000)));
271
+ const stats = `${events.length.toLocaleString()} events · ${days}d · peak ${peak}/bucket`;
272
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}">
273
+ <!-- TODO: Ed25519-signed export marker -->
274
+ <defs>
275
+ <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
276
+ <stop offset="0" stop-color="#0a1628"/>
277
+ <stop offset="1" stop-color="#0d2540"/>
278
+ </linearGradient>
279
+ <linearGradient id="barGrad" x1="0" y1="1" x2="0" y2="0">
280
+ <stop offset="0" stop-color="#00ffd5" stop-opacity="0.15"/>
281
+ <stop offset="1" stop-color="#00ffd5" stop-opacity="0.85"/>
282
+ </linearGradient>
283
+ </defs>
284
+ <rect width="${W}" height="${H}" fill="url(#bg)"/>
285
+ <text x="${PAD}" y="26" fill="#e2f5ff" font-size="16" font-family="ui-sans-serif,system-ui" font-weight="600">${esc(projName)} · Brain Replay</text>
286
+ <text x="${W - PAD}" y="26" fill="#7dd3fc" font-size="11" font-family="ui-monospace,monospace" text-anchor="end">${esc(stats)}</text>
287
+ <line x1="${PAD}" y1="${H - PAD}" x2="${W - PAD}" y2="${H - PAD}" stroke="#7dd3fc" stroke-width="0.5" opacity="0.5"/>
288
+ ${bars.join('\n ')}
289
+ ${dots.join('\n ')}
290
+ ${marks.join('\n ')}
291
+ <text x="${PAD}" y="${H - 12}" fill="#7dd3fc" font-size="10" font-family="ui-monospace,monospace" opacity="0.7">${new Date(t0).toISOString().slice(0, 10)}</text>
292
+ <text x="${W - PAD}" y="${H - 12}" fill="#7dd3fc" font-size="10" font-family="ui-monospace,monospace" text-anchor="end" opacity="0.7">${new Date(t1).toISOString().slice(0, 10)}</text>
293
+ </svg>`;
294
+ }
295
+ emptySvg(W, H, name) {
296
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}">
297
+ <defs><linearGradient id="bg" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#0a1628"/><stop offset="1" stop-color="#0d2540"/></linearGradient></defs>
298
+ <rect width="${W}" height="${H}" fill="url(#bg)"/>
299
+ <text x="${W / 2}" y="${H / 2}" fill="#7dd3fc" font-size="18" font-family="ui-sans-serif,system-ui" text-anchor="middle">${esc(name)} · awaiting first event</text>
300
+ </svg>`;
301
+ }
302
+ findMilestones(events) {
303
+ const out = [];
304
+ const entities = new Set();
305
+ let firstMemory = false;
306
+ let firstCollision = false;
307
+ for (const ev of events) {
308
+ const key = this.entityKeyOf(ev);
309
+ if (key)
310
+ entities.add(key);
311
+ if (!firstMemory && (ev.type === 'memory.write' || ev.type === 'brain.remember')) {
312
+ out.push({ ts: ev.ts, label: '1st memory' });
313
+ firstMemory = true;
314
+ }
315
+ if (entities.size === 100 && !out.find(m => m.label === '100 entities')) {
316
+ out.push({ ts: ev.ts, label: '100 entities' });
317
+ }
318
+ if (!firstCollision && ev.type.includes('collision')) {
319
+ out.push({ ts: ev.ts, label: '1st collision' });
320
+ firstCollision = true;
321
+ }
322
+ }
323
+ return out.slice(0, 6);
324
+ }
325
+ }
326
+ function esc(s) {
327
+ return String(s).replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
328
+ }
329
+ let _instance = null;
330
+ export function getBrainReplay() {
331
+ if (!_instance)
332
+ _instance = new BrainReplay();
333
+ return _instance;
334
+ }
335
+ export function resetBrainReplayForTests() { _instance = null; }
336
+ //# sourceMappingURL=brain-replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brain-replay.js","sourceRoot":"","sources":["../../src/brain/brain-replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ export interface RerankerOptions {
2
+ topNAfter?: number;
3
+ bm25Weight?: number;
4
+ cosineWeight?: number;
5
+ lengthPenalty?: boolean;
6
+ }
7
+ export interface RerankCandidate {
8
+ id: string;
9
+ text: string;
10
+ score?: number;
11
+ metadata?: Record<string, unknown>;
12
+ }
13
+ export interface RerankResult {
14
+ id: string;
15
+ text: string;
16
+ score: number;
17
+ components: {
18
+ bm25: number;
19
+ cosine: number;
20
+ lengthPenalty: number;
21
+ };
22
+ rank: number;
23
+ metadata?: Record<string, unknown>;
24
+ }
25
+ export declare class BrainRerank {
26
+ /** Rerank a candidate list using fused BM25 + cosine + optional length penalty. */
27
+ rerank(query: string, candidates: RerankCandidate[], opts?: RerankerOptions): Promise<RerankResult[]>;
28
+ /**
29
+ * Fuse with embeddings-v2: do ANN over topKFirst → rerank → return topNFinal.
30
+ * Gracefully falls back to raw ANN hits if embeddings-v2 is missing.
31
+ */
32
+ searchAndRerank(query: string, topKFirst?: number, topNFinal?: number, opts?: RerankerOptions): Promise<RerankResult[]>;
33
+ private computeBm25;
34
+ private computeCosine;
35
+ private lengthPenalty;
36
+ }
37
+ export declare function getBrainRerank(): BrainRerank;
38
+ export declare function resetBrainRerankForTests(): void;
39
+ //# sourceMappingURL=brain-rerank.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brain-rerank.d.ts","sourceRoot":"","sources":["../../src/brain/brain-rerank.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAmBD,qBAAa,WAAW;IACtB,mFAAmF;IAC7E,MAAM,CACV,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,eAAe,EAAE,EAC7B,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,YAAY,EAAE,CAAC;IAmC1B;;;OAGG;IACG,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,SAAS,SAAK,EACd,SAAS,SAAI,EACb,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,YAAY,EAAE,CAAC;IAoB1B,OAAO,CAAC,WAAW;YA4CL,aAAa;IA6B3B,OAAO,CAAC,aAAa;CAetB;AA0BD,wBAAgB,cAAc,IAAI,WAAW,CAG5C;AACD,wBAAgB,wBAAwB,IAAI,IAAI,CAAsB"}
@@ -0,0 +1,216 @@
1
+ // src/brain/brain-rerank.ts — Hybrid BM25 + cosine reranker
2
+ // v6.0.2 — Hive Mind Edition
3
+ //
4
+ // Single-pass ANN cosine is fast but noisy. Reranking the top-K candidates
5
+ // with BM25 lexical signal fused against cosine similarity dramatically
6
+ // improves recall@5 — this is the standard two-stage retrieval pattern
7
+ // (retrieve cheap & broad → rerank precise & narrow).
8
+ //
9
+ // BM25 builds a per-call inverted index over the candidate set. Fine for
10
+ // the <=500 candidate counts we see in practice. Tokenization mirrors the
11
+ // local embedding pipeline (lowercase, [^a-z0-9]+, drop short tokens +
12
+ // stopwords) so BM25 and cosine see the same surface form.
13
+ //
14
+ // Fusion: final = bm25Weight * bm25_norm + cosineWeight * cosine_norm
15
+ // minus an optional length penalty for too-short / too-long docs.
16
+ // All component scores are normalized to [0, 1] within the result set so
17
+ // the weights are interpretable as direct contribution ratios.
18
+ //
19
+ // Composes with embeddings-v2 via dynamic import — graceful fallback when
20
+ // the ANN index is unavailable or empty.
21
+ //
22
+ // Exposed: BrainRerank, getBrainRerank(), resetBrainRerankForTests().
23
+ // .rerank(query, candidates, opts)
24
+ // .searchAndRerank(query, topKFirst, topNFinal, opts)
25
+ import { getEmbeddings } from './embeddings.js';
26
+ const DEFAULT_TOP_N = 5;
27
+ const DEFAULT_BM25_WEIGHT = 0.4;
28
+ const DEFAULT_COSINE_WEIGHT = 0.6;
29
+ const BM25_K1 = 1.5;
30
+ const BM25_B = 0.75;
31
+ const MIN_TOKEN_LEN = 2;
32
+ const SHORT_DOC_CHARS = 20;
33
+ const LONG_DOC_CHARS = 2000;
34
+ const LENGTH_PENALTY_FACTOR = 0.15;
35
+ const STOPWORDS = new Set([
36
+ 'the', 'a', 'an', 'and', 'or', 'of', 'to', 'for', 'in', 'on', 'is', 'it', 'this', 'that',
37
+ 'as', 'by', 'be', 'do', 'at', 'if', 'so', 'no', 'not', 'but', 'from', 'with', 'was', 'were',
38
+ 'are', 'am', 'i', 'you', 'he', 'she', 'we', 'they', 'my', 'your', 'our', 'their', 'its',
39
+ 'me', 'us', 'them', 'then', 'than', 'too', 'very', 'can', 'will', 'just', 'about', 'into',
40
+ ]);
41
+ export class BrainRerank {
42
+ /** Rerank a candidate list using fused BM25 + cosine + optional length penalty. */
43
+ async rerank(query, candidates, opts) {
44
+ if (!candidates || candidates.length === 0)
45
+ return [];
46
+ const topN = opts?.topNAfter ?? DEFAULT_TOP_N;
47
+ const wBm25 = opts?.bm25Weight ?? DEFAULT_BM25_WEIGHT;
48
+ const wCos = opts?.cosineWeight ?? DEFAULT_COSINE_WEIGHT;
49
+ const usePenalty = opts?.lengthPenalty !== false;
50
+ const bm25Scores = this.computeBm25(query, candidates);
51
+ const cosineScores = await this.computeCosine(query, candidates);
52
+ const penaltyScores = usePenalty
53
+ ? candidates.map(c => this.lengthPenalty(c.text))
54
+ : candidates.map(() => 0);
55
+ const bm25Norm = normalize01(bm25Scores);
56
+ const cosNorm = normalize01(cosineScores);
57
+ const fused = candidates.map((c, i) => {
58
+ const score = wBm25 * bm25Norm[i] + wCos * cosNorm[i] - penaltyScores[i];
59
+ return {
60
+ id: c.id,
61
+ text: c.text,
62
+ score,
63
+ components: { bm25: bm25Norm[i], cosine: cosNorm[i], lengthPenalty: penaltyScores[i] },
64
+ rank: 0,
65
+ metadata: c.metadata,
66
+ };
67
+ });
68
+ fused.sort((a, b) => b.score - a.score);
69
+ const sliced = fused.slice(0, topN);
70
+ sliced.forEach((r, idx) => { r.rank = idx + 1; });
71
+ return sliced;
72
+ }
73
+ /**
74
+ * Fuse with embeddings-v2: do ANN over topKFirst → rerank → return topNFinal.
75
+ * Gracefully falls back to raw ANN hits if embeddings-v2 is missing.
76
+ */
77
+ async searchAndRerank(query, topKFirst = 50, topNFinal = 5, opts) {
78
+ let hits = [];
79
+ try {
80
+ const mod = await import('./embeddings-v2.js');
81
+ const v2 = mod.getEmbeddingsV2();
82
+ hits = await v2.search(query, topKFirst);
83
+ }
84
+ catch {
85
+ return [];
86
+ }
87
+ if (hits.length === 0)
88
+ return [];
89
+ return this.rerank(query, hits.map(h => ({ id: h.id, text: h.text, score: h.score, metadata: h.metadata })), { ...opts, topNAfter: topNFinal });
90
+ }
91
+ // ── BM25 ──────────────────────────────────────────────────────────────
92
+ computeBm25(query, candidates) {
93
+ const queryTerms = tokenize(query);
94
+ if (queryTerms.length === 0)
95
+ return candidates.map(() => 0);
96
+ const docTokens = candidates.map(c => tokenize(c.text));
97
+ const docLens = docTokens.map(t => t.length);
98
+ const N = candidates.length;
99
+ const avgDl = docLens.reduce((s, x) => s + x, 0) / Math.max(1, N);
100
+ // Document frequency per query term
101
+ const df = new Map();
102
+ for (const term of queryTerms) {
103
+ if (df.has(term))
104
+ continue;
105
+ let count = 0;
106
+ for (const toks of docTokens) {
107
+ if (toks.includes(term))
108
+ count++;
109
+ }
110
+ df.set(term, count);
111
+ }
112
+ // Per-doc score
113
+ const scores = [];
114
+ for (let i = 0; i < N; i++) {
115
+ const toks = docTokens[i];
116
+ const dl = docLens[i] || 1;
117
+ const tf = new Map();
118
+ for (const t of toks)
119
+ tf.set(t, (tf.get(t) ?? 0) + 1);
120
+ let s = 0;
121
+ for (const term of queryTerms) {
122
+ const f = tf.get(term);
123
+ if (!f)
124
+ continue;
125
+ const dfT = df.get(term) ?? 0;
126
+ const idf = Math.log((N - dfT + 0.5) / (dfT + 0.5) + 1);
127
+ const norm = 1 - BM25_B + BM25_B * (dl / avgDl);
128
+ s += idf * ((f * (BM25_K1 + 1)) / (f + BM25_K1 * norm));
129
+ }
130
+ scores.push(s);
131
+ }
132
+ return scores;
133
+ }
134
+ // ── Cosine ────────────────────────────────────────────────────────────
135
+ async computeCosine(query, candidates) {
136
+ // If every candidate already has a usable score, reuse it (saves embedding work).
137
+ const allHaveScores = candidates.every(c => typeof c.score === 'number' && Number.isFinite(c.score));
138
+ if (allHaveScores)
139
+ return candidates.map(c => c.score ?? 0);
140
+ try {
141
+ const emb = getEmbeddings();
142
+ const q = await emb.embed(query);
143
+ const out = [];
144
+ for (const c of candidates) {
145
+ if (typeof c.score === 'number' && Number.isFinite(c.score)) {
146
+ out.push(c.score);
147
+ continue;
148
+ }
149
+ const v = await emb.embed(c.text);
150
+ let dotP = 0;
151
+ const n = Math.min(q.length, v.length);
152
+ for (let i = 0; i < n; i++)
153
+ dotP += q[i] * v[i];
154
+ out.push(dotP);
155
+ }
156
+ return out;
157
+ }
158
+ catch {
159
+ // Defensive: degrade to whatever scores we have (or zeros).
160
+ return candidates.map(c => c.score ?? 0);
161
+ }
162
+ }
163
+ // ── Length penalty ────────────────────────────────────────────────────
164
+ lengthPenalty(text) {
165
+ const len = text?.length ?? 0;
166
+ if (len === 0)
167
+ return LENGTH_PENALTY_FACTOR;
168
+ if (len < SHORT_DOC_CHARS) {
169
+ const overflow = SHORT_DOC_CHARS - len;
170
+ const total = SHORT_DOC_CHARS;
171
+ return LENGTH_PENALTY_FACTOR * (overflow / total);
172
+ }
173
+ if (len > LONG_DOC_CHARS) {
174
+ const overflow = len - LONG_DOC_CHARS;
175
+ const total = LONG_DOC_CHARS;
176
+ return LENGTH_PENALTY_FACTOR * Math.min(1, overflow / total);
177
+ }
178
+ return 0;
179
+ }
180
+ }
181
+ function tokenize(text) {
182
+ if (!text)
183
+ return [];
184
+ return text
185
+ .toLowerCase()
186
+ .split(/[^a-z0-9]+/)
187
+ .filter(t => t.length >= MIN_TOKEN_LEN && !STOPWORDS.has(t));
188
+ }
189
+ function normalize01(scores) {
190
+ if (scores.length === 0)
191
+ return [];
192
+ let min = Infinity;
193
+ let max = -Infinity;
194
+ for (const s of scores) {
195
+ if (!Number.isFinite(s))
196
+ continue;
197
+ if (s < min)
198
+ min = s;
199
+ if (s > max)
200
+ max = s;
201
+ }
202
+ if (!Number.isFinite(min) || !Number.isFinite(max))
203
+ return scores.map(() => 0);
204
+ const range = max - min;
205
+ if (range <= 0)
206
+ return scores.map(() => (max > 0 ? 1 : 0));
207
+ return scores.map(s => (Number.isFinite(s) ? (s - min) / range : 0));
208
+ }
209
+ let _instance = null;
210
+ export function getBrainRerank() {
211
+ if (!_instance)
212
+ _instance = new BrainRerank();
213
+ return _instance;
214
+ }
215
+ export function resetBrainRerankForTests() { _instance = null; }
216
+ //# sourceMappingURL=brain-rerank.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brain-rerank.js","sourceRoot":"","sources":["../../src/brain/brain-rerank.ts"],"names":[],"mappings":"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"}