@psiclawops/hypermem 0.8.5 → 0.9.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/INSTALL.md +132 -9
  3. package/README.md +119 -272
  4. package/bench/README.md +42 -0
  5. package/bench/data-access-bench.mjs +380 -0
  6. package/bin/hypermem-bench.mjs +2 -0
  7. package/bin/hypermem-doctor.mjs +412 -0
  8. package/bin/hypermem-model-audit.mjs +339 -0
  9. package/bin/hypermem-status.mjs +491 -70
  10. package/dist/adaptive-lifecycle.d.ts +81 -0
  11. package/dist/adaptive-lifecycle.d.ts.map +1 -0
  12. package/dist/adaptive-lifecycle.js +190 -0
  13. package/dist/budget-policy.d.ts +1 -1
  14. package/dist/budget-policy.d.ts.map +1 -1
  15. package/dist/budget-policy.js +10 -5
  16. package/dist/cache.d.ts +1 -0
  17. package/dist/cache.d.ts.map +1 -1
  18. package/dist/cache.js +2 -0
  19. package/dist/composition-snapshot-integrity.d.ts +36 -0
  20. package/dist/composition-snapshot-integrity.d.ts.map +1 -0
  21. package/dist/composition-snapshot-integrity.js +131 -0
  22. package/dist/composition-snapshot-runtime.d.ts +59 -0
  23. package/dist/composition-snapshot-runtime.d.ts.map +1 -0
  24. package/dist/composition-snapshot-runtime.js +250 -0
  25. package/dist/composition-snapshot-store.d.ts +44 -0
  26. package/dist/composition-snapshot-store.d.ts.map +1 -0
  27. package/dist/composition-snapshot-store.js +117 -0
  28. package/dist/compositor.d.ts +125 -1
  29. package/dist/compositor.d.ts.map +1 -1
  30. package/dist/compositor.js +692 -44
  31. package/dist/doc-chunk-store.d.ts +19 -0
  32. package/dist/doc-chunk-store.d.ts.map +1 -1
  33. package/dist/doc-chunk-store.js +56 -6
  34. package/dist/hybrid-retrieval.d.ts +38 -0
  35. package/dist/hybrid-retrieval.d.ts.map +1 -1
  36. package/dist/hybrid-retrieval.js +86 -1
  37. package/dist/index.d.ts +12 -3
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +28 -2
  40. package/dist/knowledge-store.d.ts +4 -1
  41. package/dist/knowledge-store.d.ts.map +1 -1
  42. package/dist/knowledge-store.js +27 -4
  43. package/dist/library-schema.d.ts +12 -8
  44. package/dist/library-schema.d.ts.map +1 -1
  45. package/dist/library-schema.js +22 -8
  46. package/dist/message-store.d.ts.map +1 -1
  47. package/dist/message-store.js +7 -3
  48. package/dist/metrics-dashboard.d.ts +18 -1
  49. package/dist/metrics-dashboard.d.ts.map +1 -1
  50. package/dist/metrics-dashboard.js +52 -14
  51. package/dist/reranker.d.ts +1 -1
  52. package/dist/reranker.js +2 -2
  53. package/dist/schema.d.ts +1 -1
  54. package/dist/schema.d.ts.map +1 -1
  55. package/dist/schema.js +28 -1
  56. package/dist/seed.d.ts.map +1 -1
  57. package/dist/seed.js +2 -0
  58. package/dist/topic-synthesizer.d.ts +20 -0
  59. package/dist/topic-synthesizer.d.ts.map +1 -1
  60. package/dist/topic-synthesizer.js +113 -3
  61. package/dist/trigger-registry.d.ts.map +1 -1
  62. package/dist/trigger-registry.js +10 -2
  63. package/dist/types.d.ts +271 -1
  64. package/dist/types.d.ts.map +1 -1
  65. package/dist/version.d.ts +7 -7
  66. package/dist/version.d.ts.map +1 -1
  67. package/dist/version.js +17 -7
  68. package/docs/DIAGNOSTICS.md +205 -0
  69. package/docs/INTEGRATION_VALIDATION.md +186 -0
  70. package/docs/MIGRATION.md +9 -6
  71. package/docs/MIGRATION_GUIDE.md +125 -101
  72. package/docs/ROADMAP.md +238 -20
  73. package/docs/TUNING.md +19 -5
  74. package/install.sh +152 -401
  75. package/memory-plugin/LICENSE +190 -0
  76. package/memory-plugin/README.md +20 -0
  77. package/memory-plugin/dist/index.js +50 -0
  78. package/memory-plugin/package.json +2 -2
  79. package/package.json +18 -4
  80. package/plugin/LICENSE +190 -0
  81. package/plugin/README.md +20 -0
  82. package/plugin/dist/index.d.ts +29 -0
  83. package/plugin/dist/index.d.ts.map +1 -1
  84. package/plugin/dist/index.js +288 -23
  85. package/plugin/dist/index.js.map +1 -1
  86. package/plugin/package.json +2 -2
  87. package/scripts/install-runtime.mjs +12 -1
@@ -1 +1 @@
1
- {"version":3,"file":"library-schema.d.ts","sourceRoot":"","sources":["../src/library-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAo6BzC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAkF3G;AAID,wBAAgB,cAAc,CAAC,EAAE,EAAE,YAAY,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAuZ7E"}
1
+ {"version":3,"file":"library-schema.d.ts","sourceRoot":"","sources":["../src/library-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAo6BzC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAkF3G;AAID,wBAAgB,cAAc,CAAC,EAAE,EAAE,YAAY,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAoa7E"}
@@ -6,15 +6,19 @@
6
6
  *
7
7
  * Collections:
8
8
  * 1. Library entries (versioned docs, specs, reference material)
9
- * 2. Facts (agent-learned truths)
9
+ * 2. Facts (agent-learned truths with confidence, visibility, temporal validity)
10
10
  * 3. Preferences (behavioral patterns)
11
- * 4. Knowledge (structured domain knowledge, supersedable)
12
- * 5. Episodes (significant events)
13
- * 6. Fleet registry (agents, orgs)
14
- * 7. System registry (server state, config)
15
- * 8. Session registry (lifecycle tracking)
16
- * 9. Work items (fleet kanban)
17
- * 10. Topics (cross-session thread tracking)
11
+ * 4. Knowledge/wiki (structured domain knowledge, supersedable topic syntheses)
12
+ * 5. Episodes (significant events, decisions, discoveries)
13
+ * 6. Topics (cross-session thread tracking)
14
+ * 7. Knowledge graph links (relationships between facts, knowledge, topics, episodes)
15
+ * 8. Fleet registry (agents, orgs, capabilities)
16
+ * 9. Desired state and config events (drift detection)
17
+ * 10. System registry and work items (server state, work queues, events)
18
+ * 11. Session registry and lifecycle events
19
+ * 12. Document sources/chunks and trigger retrieval metadata
20
+ * 13. Output standards, model directives, and output metrics
21
+ * 14. Temporal index, expertise patterns, contradiction audits, and indexer watermarks
18
22
  */
19
23
  import { DatabaseSync } from 'node:sqlite';
20
24
  import { mkdirSync, renameSync, existsSync } from 'node:fs';
@@ -1321,6 +1325,16 @@ export function migrateLibrary(db, engineVersion) {
1321
1325
  db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)')
1322
1326
  .run(19, nowIso());
1323
1327
  }
1328
+ // Always repair knowledge schema drift before runtime writes.
1329
+ // Some long-lived databases reached schema >=7 with the versioned knowledge
1330
+ // table present but without the visibility column. KnowledgeStore writes
1331
+ // require visibility, and synthesis/indexer upserts otherwise fail at runtime
1332
+ // even though schema_version says the migration already ran.
1333
+ const knowledgeCols = new Set(db.prepare('PRAGMA table_info(knowledge)').all().map(col => col.name));
1334
+ if (!knowledgeCols.has('visibility')) {
1335
+ db.exec("ALTER TABLE knowledge ADD COLUMN visibility TEXT NOT NULL DEFAULT 'private'");
1336
+ }
1337
+ db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_visibility ON knowledge(visibility, agent_id)');
1324
1338
  // Always ensure meta exists before stamping the running engine version.
1325
1339
  // Some legacy/stale DBs reached schema >=10 without the V10 migration having
1326
1340
  // actually created the table, which would make startup fail with
@@ -1 +1 @@
1
- {"version":3,"file":"message-store.d.ts","sourceRoot":"","sources":["../src/message-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"message-store.d.ts","sourceRoot":"","sources":["../src/message-store.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,9 @@ function parseMessageRow(row) {
21
21
  textContent: row.text_content || null,
22
22
  toolCalls: row.tool_calls ? JSON.parse(row.tool_calls) : null,
23
23
  toolResults: row.tool_results ? JSON.parse(row.tool_results) : null,
24
+ topicId: typeof row.topic_id === 'string' && row.topic_id.length > 0
25
+ ? row.topic_id
26
+ : undefined,
24
27
  metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
25
28
  messageIndex: row.message_index,
26
29
  tokenCount: row.token_count || null,
@@ -179,9 +182,9 @@ export class MessageStore {
179
182
  }
180
183
  }
181
184
  const result = this.db.prepare(`
182
- INSERT INTO messages (conversation_id, agent_id, role, text_content, tool_calls, tool_results, metadata, token_count, message_index, is_heartbeat, created_at, context_id, parent_id, depth)
183
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
184
- `).run(conversationId, agentId, message.role, message.textContent, message.toolCalls ? JSON.stringify(message.toolCalls) : null, message.toolResults ? JSON.stringify(message.toolResults) : null, message.metadata ? JSON.stringify(message.metadata) : null, opts?.tokenCount || null, messageIndex, opts?.isHeartbeat ? 1 : 0, now, opts?.contextId ?? null, parentId, depth);
185
+ INSERT INTO messages (conversation_id, agent_id, role, text_content, tool_calls, tool_results, metadata, token_count, message_index, is_heartbeat, created_at, context_id, parent_id, depth, topic_id)
186
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
187
+ `).run(conversationId, agentId, message.role, message.textContent, message.toolCalls ? JSON.stringify(message.toolCalls) : null, message.toolResults ? JSON.stringify(message.toolResults) : null, message.metadata ? JSON.stringify(message.metadata) : null, opts?.tokenCount || null, messageIndex, opts?.isHeartbeat ? 1 : 0, now, opts?.contextId ?? null, parentId, depth, message.topicId ?? null);
185
188
  const id = result.lastInsertRowid;
186
189
  // Update context head pointer if contextId was provided
187
190
  if (opts?.contextId) {
@@ -206,6 +209,7 @@ export class MessageStore {
206
209
  textContent: message.textContent,
207
210
  toolCalls: message.toolCalls,
208
211
  toolResults: message.toolResults,
212
+ topicId: message.topicId,
209
213
  metadata: message.metadata,
210
214
  messageIndex,
211
215
  tokenCount: opts?.tokenCount || null,
@@ -44,6 +44,14 @@ export interface VectorMetrics {
44
44
  /** Embedding cache hit rate (0-1) for this process lifetime */
45
45
  cacheHitRate: number | null;
46
46
  }
47
+ export interface DocChunkMetrics {
48
+ /** Total doc chunks indexed across all collections */
49
+ totalDocChunks: number;
50
+ /** Doc chunks per collection */
51
+ byCollection: Record<string, number>;
52
+ /** Doc chunks added in the last 24h */
53
+ recentDocChunks: number;
54
+ }
47
55
  export interface CompositionMetrics {
48
56
  /** Average assembly time in ms (from output_metrics table) */
49
57
  avgAssemblyMs: number | null;
@@ -81,6 +89,10 @@ export interface SystemHealth {
81
89
  librarySchemaVersion: number | null;
82
90
  /** hypermem package version */
83
91
  packageVersion: string;
92
+ /** Resolved embedding provider from the installed config */
93
+ embeddingProvider: string | null;
94
+ /** Resolved embedding model from the installed config */
95
+ embeddingModel: string | null;
84
96
  /** Cache connection status (if provided) */
85
97
  cacheOk: boolean | null;
86
98
  /** Timestamp of this snapshot */
@@ -88,6 +100,7 @@ export interface SystemHealth {
88
100
  }
89
101
  export interface HyperMemMetrics {
90
102
  facts: FactMetrics;
103
+ docChunks: DocChunkMetrics;
91
104
  wiki: WikiMetrics;
92
105
  episodes: EpisodeMetrics;
93
106
  vectors: VectorMetrics;
@@ -100,12 +113,16 @@ export interface MetricsDashboardOptions {
100
113
  agentIds?: string[];
101
114
  /** Include per-agent breakdowns. Default: true */
102
115
  includeBreakdowns?: boolean;
116
+ /** Resolved embedding provider for health display. */
117
+ embeddingProvider?: string | null;
118
+ /** Resolved embedding model for health display. */
119
+ embeddingModel?: string | null;
103
120
  }
104
121
  /**
105
122
  * Collect all metrics in a single pass.
106
123
  * Safe to call on live DBs — all queries are read-only.
107
124
  */
108
- export declare function collectMetrics(mainDb: DatabaseSync, libraryDb: DatabaseSync, opts?: MetricsDashboardOptions): Promise<HyperMemMetrics>;
125
+ export declare function collectMetrics(mainDb: DatabaseSync, libraryDb: DatabaseSync, opts?: MetricsDashboardOptions, vectorDb?: DatabaseSync | null): Promise<HyperMemMetrics>;
109
126
  /**
110
127
  * Format metrics as a human-readable summary string.
111
128
  * Suitable for logging or status replies.
@@ -1 +1 @@
1
- {"version":3,"file":"metrics-dashboard.d.ts","sourceRoot":"","sources":["../src/metrics-dashboard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metrics-dashboard.d.ts","sourceRoot":"","sources":["../src/metrics-dashboard.ts"],"names":[],"mappings":"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"}
@@ -51,6 +51,23 @@ function collectFactMetrics(libraryDb, opts) {
51
51
  recentFacts: recent?.count ?? 0,
52
52
  };
53
53
  }
54
+ /**
55
+ * Collect doc chunk metrics from the library DB.
56
+ */
57
+ function collectDocChunkMetrics(libraryDb, opts) {
58
+ const { clause, params } = buildAgentFilter(opts.agentIds);
59
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
60
+ const total = safeQuery(libraryDb, `SELECT COUNT(*) AS count FROM doc_chunks WHERE 1=1 ${clause}`, params);
61
+ const recent = safeQuery(libraryDb, `SELECT COUNT(*) AS count FROM doc_chunks WHERE created_at > ? ${clause}`, [cutoff, ...params]);
62
+ const byCollectionRows = (opts.includeBreakdowns !== false)
63
+ ? safeQueryAll(libraryDb, `SELECT collection, COUNT(*) AS count FROM doc_chunks WHERE 1=1 ${clause} GROUP BY collection`, params)
64
+ : [];
65
+ return {
66
+ totalDocChunks: total?.count ?? 0,
67
+ byCollection: Object.fromEntries(byCollectionRows.map(r => [r.collection, r.count])),
68
+ recentDocChunks: recent?.count ?? 0,
69
+ };
70
+ }
54
71
  /**
55
72
  * Collect wiki page metrics from the library DB (knowledge table, topic-synthesis domain).
56
73
  */
@@ -92,11 +109,18 @@ function collectEpisodeMetrics(libraryDb, opts) {
92
109
  };
93
110
  }
94
111
  /**
95
- * Collect vector index metrics from the library DB.
112
+ * Collect vector index metrics from the shared vectors DB.
96
113
  */
97
- function collectVectorMetrics(libraryDb) {
98
- const total = safeQuery(libraryDb, 'SELECT COUNT(*) as cnt FROM vec_index_map');
99
- const byTableRows = safeQueryAll(libraryDb, 'SELECT source_table, COUNT(*) as cnt FROM vec_index_map GROUP BY source_table');
114
+ function collectVectorMetrics(vectorDb) {
115
+ if (!vectorDb) {
116
+ return {
117
+ totalVectors: 0,
118
+ byTable: {},
119
+ cacheHitRate: null,
120
+ };
121
+ }
122
+ const total = safeQuery(vectorDb, 'SELECT COUNT(*) as cnt FROM vec_index_map');
123
+ const byTableRows = safeQueryAll(vectorDb, 'SELECT source_table, COUNT(*) as cnt FROM vec_index_map GROUP BY source_table');
100
124
  return {
101
125
  totalVectors: total?.cnt ?? 0,
102
126
  byTable: Object.fromEntries(byTableRows.map(r => [r.source_table, r.cnt])),
@@ -104,11 +128,11 @@ function collectVectorMetrics(libraryDb) {
104
128
  };
105
129
  }
106
130
  /**
107
- * Collect composition performance metrics from the output_metrics table (main DB).
131
+ * Collect composition performance metrics from the output_metrics table (library DB).
108
132
  */
109
- function collectCompositionMetrics(mainDb, opts) {
133
+ function collectCompositionMetrics(libraryDb, opts) {
110
134
  const { clause, params } = buildAgentFilter(opts.agentIds);
111
- const agg = safeQuery(mainDb, `SELECT
135
+ const agg = safeQuery(libraryDb, `SELECT
112
136
  AVG(latency_ms) AS avg_latency,
113
137
  AVG(output_tokens) AS avg_output,
114
138
  AVG(input_tokens) AS avg_input,
@@ -118,12 +142,12 @@ function collectCompositionMetrics(mainDb, opts) {
118
142
  // p95: sort latency_ms and pick the 95th percentile row
119
143
  let p95 = null;
120
144
  if ((agg?.total ?? 0) > 0) {
121
- const p95Row = safeQuery(mainDb, `SELECT latency_ms FROM output_metrics WHERE latency_ms IS NOT NULL ${clause}
145
+ const p95Row = safeQuery(libraryDb, `SELECT latency_ms FROM output_metrics WHERE latency_ms IS NOT NULL ${clause}
122
146
  ORDER BY latency_ms ASC
123
147
  LIMIT 1 OFFSET MAX(0, CAST(COUNT(*) * 0.95 AS INT) - 1)`, params);
124
148
  // Fallback: approximate p95 with a subquery
125
149
  if (!p95Row) {
126
- const p95Approx = safeQuery(mainDb, `SELECT latency_ms FROM output_metrics WHERE latency_ms IS NOT NULL ${clause}
150
+ const p95Approx = safeQuery(libraryDb, `SELECT latency_ms FROM output_metrics WHERE latency_ms IS NOT NULL ${clause}
127
151
  ORDER BY latency_ms DESC
128
152
  LIMIT 1 OFFSET (SELECT MAX(0, CAST(COUNT(*) * 0.05 AS INT)) FROM output_metrics WHERE latency_ms IS NOT NULL ${clause})`, [...params, ...params]);
129
153
  p95 = p95Approx?.latency_ms ?? null;
@@ -165,7 +189,7 @@ function collectIngestionMetrics(libraryDb, opts) {
165
189
  /**
166
190
  * Collect system health from both DBs.
167
191
  */
168
- function collectHealth(mainDb, libraryDb) {
192
+ function collectHealth(mainDb, libraryDb, opts) {
169
193
  let mainSchemaVersion = null;
170
194
  let librarySchemaVersion = null;
171
195
  let mainDbOk = false;
@@ -188,6 +212,8 @@ function collectHealth(mainDb, libraryDb) {
188
212
  mainSchemaVersion,
189
213
  librarySchemaVersion,
190
214
  packageVersion: HYPERMEM_COMPAT_VERSION,
215
+ embeddingProvider: opts.embeddingProvider ?? null,
216
+ embeddingModel: opts.embeddingModel ?? null,
191
217
  cacheOk: null, // caller must inject cache status
192
218
  snapshotAt: new Date().toISOString(),
193
219
  };
@@ -196,15 +222,16 @@ function collectHealth(mainDb, libraryDb) {
196
222
  * Collect all metrics in a single pass.
197
223
  * Safe to call on live DBs — all queries are read-only.
198
224
  */
199
- export async function collectMetrics(mainDb, libraryDb, opts = {}) {
225
+ export async function collectMetrics(mainDb, libraryDb, opts = {}, vectorDb = null) {
200
226
  return {
201
227
  facts: collectFactMetrics(libraryDb, opts),
228
+ docChunks: collectDocChunkMetrics(libraryDb, opts),
202
229
  wiki: collectWikiMetrics(libraryDb, opts),
203
230
  episodes: collectEpisodeMetrics(libraryDb, opts),
204
- vectors: collectVectorMetrics(libraryDb),
205
- composition: collectCompositionMetrics(mainDb, opts),
231
+ vectors: collectVectorMetrics(vectorDb),
232
+ composition: collectCompositionMetrics(libraryDb, opts),
206
233
  ingestion: collectIngestionMetrics(libraryDb, opts),
207
- health: collectHealth(mainDb, libraryDb),
234
+ health: collectHealth(mainDb, libraryDb, opts),
208
235
  };
209
236
  }
210
237
  /**
@@ -217,6 +244,12 @@ export function formatMetricsSummary(m) {
217
244
  lines.push('');
218
245
  lines.push('## Memory');
219
246
  lines.push(` facts: ${m.facts.totalFacts.toLocaleString()} total, ${m.facts.recentFacts} added last 24h`);
247
+ lines.push(` doc chunks: ${m.docChunks.totalDocChunks.toLocaleString()} total, ${m.docChunks.recentDocChunks} added last 24h`);
248
+ if (Object.keys(m.docChunks.byCollection).length > 0) {
249
+ for (const [collection, count] of Object.entries(m.docChunks.byCollection)) {
250
+ lines.push(` ${collection}: ${count.toLocaleString()}`);
251
+ }
252
+ }
220
253
  lines.push(` wiki: ${m.wiki.totalPages} pages, ${m.wiki.recentPages} synthesized last 24h${m.wiki.oldestPageAgeHours !== null ? `, oldest ${m.wiki.oldestPageAgeHours}h` : ''}`);
221
254
  lines.push(` episodes: ${m.episodes.totalEpisodes.toLocaleString()}${m.episodes.avgSignificance !== null ? `, avg significance ${m.episodes.avgSignificance.toFixed(2)}` : ''}`);
222
255
  lines.push(` vectors: ${m.vectors.totalVectors.toLocaleString()} indexed`);
@@ -226,6 +259,10 @@ export function formatMetricsSummary(m) {
226
259
  }
227
260
  }
228
261
  lines.push('');
262
+ lines.push('## Embedding');
263
+ lines.push(` provider: ${m.health.embeddingProvider ?? 'unknown'}`);
264
+ lines.push(` model: ${m.health.embeddingModel ?? 'unknown'}`);
265
+ lines.push('');
229
266
  lines.push('## Composition');
230
267
  if (m.composition.totalTurns > 0) {
231
268
  lines.push(` turns: ${m.composition.totalTurns.toLocaleString()}`);
@@ -250,6 +287,7 @@ export function formatMetricsSummary(m) {
250
287
  lines.push(` knowledge promoted: ${m.ingestion.totalKnowledgePromoted.toLocaleString()}`);
251
288
  lines.push('');
252
289
  lines.push('## Health');
290
+ lines.push(` embedding: ${m.health.embeddingProvider ?? 'unknown'}${m.health.embeddingModel ? ` / ${m.health.embeddingModel}` : ''}`);
253
291
  lines.push(` main db: ${m.health.mainDbOk ? '✅' : '❌'}${m.health.mainSchemaVersion !== null ? ` (schema v${m.health.mainSchemaVersion})` : ''}`);
254
292
  lines.push(` library db: ${m.health.libraryDbOk ? '✅' : '❌'}${m.health.librarySchemaVersion !== null ? ` (schema v${m.health.librarySchemaVersion})` : ''}`);
255
293
  if (m.health.cacheOk !== null) {
@@ -6,7 +6,7 @@
6
6
  * order without disruption.
7
7
  *
8
8
  * Providers:
9
- * - ZeroEntropyReranker — https://api.zeroentropy.dev/v1/rerank (zerank-2)
9
+ * - ZeroEntropyReranker — https://api.zeroentropy.dev/v1/models/rerank (zerank-2)
10
10
  * - OpenRouterReranker — https://openrouter.ai/api/v1/rerank (cohere/rerank-4-pro)
11
11
  * - OllamaReranker — http://localhost:11434/api/chat (yes/no classification)
12
12
  *
package/dist/reranker.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * order without disruption.
7
7
  *
8
8
  * Providers:
9
- * - ZeroEntropyReranker — https://api.zeroentropy.dev/v1/rerank (zerank-2)
9
+ * - ZeroEntropyReranker — https://api.zeroentropy.dev/v1/models/rerank (zerank-2)
10
10
  * - OpenRouterReranker — https://openrouter.ai/api/v1/rerank (cohere/rerank-4-pro)
11
11
  * - OllamaReranker — http://localhost:11434/api/chat (yes/no classification)
12
12
  *
@@ -100,7 +100,7 @@ export class ZeroEntropyReranker {
100
100
  return null;
101
101
  const { controller, clear } = withTimeout(this.timeoutMs);
102
102
  try {
103
- const response = await fetch('https://api.zeroentropy.dev/v1/rerank', {
103
+ const response = await fetch('https://api.zeroentropy.dev/v1/models/rerank', {
104
104
  method: 'POST',
105
105
  headers: {
106
106
  'Content-Type': 'application/json',
package/dist/schema.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * Contains ONLY conversation data — structured knowledge lives in library.db.
7
7
  */
8
8
  import type { DatabaseSync } from 'node:sqlite';
9
- export declare const LATEST_SCHEMA_VERSION = 10;
9
+ export declare const LATEST_SCHEMA_VERSION = 11;
10
10
  /**
11
11
  * Run migrations on an agent message database.
12
12
  */
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAgJxC;;GAEG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA0K9C;AAED,OAAO,EAAE,qBAAqB,IAAI,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAgJxC;;GAEG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAsM9C;AAED,OAAO,EAAE,qBAAqB,IAAI,cAAc,EAAE,CAAC"}
package/dist/schema.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * Write-heavy, temporal, rotatable.
6
6
  * Contains ONLY conversation data — structured knowledge lives in library.db.
7
7
  */
8
- export const LATEST_SCHEMA_VERSION = 10;
8
+ export const LATEST_SCHEMA_VERSION = 11;
9
9
  function nowIso() {
10
10
  return new Date().toISOString();
11
11
  }
@@ -295,6 +295,33 @@ export function migrate(db) {
295
295
  db.prepare('INSERT OR IGNORE INTO schema_version (version, applied_at) VALUES (?, ?)')
296
296
  .run(10, nowIso());
297
297
  }
298
+ // v10 → v11: composition snapshot sidecar for warm-restore capture.
299
+ if (currentVersion < 11) {
300
+ db.exec(`
301
+ CREATE TABLE IF NOT EXISTS composition_snapshots (
302
+ id INTEGER PRIMARY KEY,
303
+ context_id INTEGER NOT NULL REFERENCES contexts(id) ON DELETE CASCADE,
304
+ head_message_id INTEGER REFERENCES messages(id),
305
+ schema_version INTEGER NOT NULL DEFAULT 1,
306
+ captured_at TEXT NOT NULL,
307
+ model TEXT NOT NULL,
308
+ context_window INTEGER NOT NULL,
309
+ total_tokens INTEGER NOT NULL,
310
+ fill_pct REAL NOT NULL,
311
+ snapshot_kind TEXT NOT NULL DEFAULT 'full',
312
+ repair_depth INTEGER NOT NULL DEFAULT 0,
313
+ slots_json TEXT NOT NULL,
314
+ slots_integrity_hash TEXT NOT NULL,
315
+ created_at TEXT NOT NULL
316
+ )
317
+ `);
318
+ db.exec(`
319
+ CREATE INDEX IF NOT EXISTS idx_composition_snapshots_context_recent
320
+ ON composition_snapshots(context_id, captured_at DESC)
321
+ `);
322
+ db.prepare('INSERT OR IGNORE INTO schema_version (version, applied_at) VALUES (?, ?)')
323
+ .run(11, nowIso());
324
+ }
298
325
  }
299
326
  export { LATEST_SCHEMA_VERSION as SCHEMA_VERSION };
300
327
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIvE,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,mEAAmE;IACnE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,mCAAmC;IACnC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,gCAAgC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAID,qBAAa,eAAe;IAGd,OAAO,CAAC,EAAE;IAFtB,OAAO,CAAC,UAAU,CAAgB;gBAEd,EAAE,EAAE,OAAO,aAAa,EAAE,YAAY;IAI1D;;OAEG;IACG,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAmDtF;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,cAAc;IAmBtF;;OAEG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,KAAK,CAAC;QAClE,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;IAeF;;OAEG;IACH,aAAa;;;;;;IAIb;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAMhH,OAAO,CAAC,aAAa;CAuCtB;AAID;;;GAGG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,OAAO,aAAa,EAAE,YAAY,EACtC,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,UAAU,CAAC,CAGrB"}
1
+ {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIvE,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,mEAAmE;IACnE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,mCAAmC;IACnC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,gCAAgC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAID,qBAAa,eAAe;IAGd,OAAO,CAAC,EAAE;IAFtB,OAAO,CAAC,UAAU,CAAgB;gBAEd,EAAE,EAAE,OAAO,aAAa,EAAE,YAAY;IAI1D;;OAEG;IACG,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAsDtF;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,cAAc;IAmBtF;;OAEG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,KAAK,CAAC;QAClE,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;IAeF;;OAEG;IACH,aAAa;;;;;;IAIb;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAMhH,OAAO,CAAC,aAAa;CAuCtB;AAID;;;GAGG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,OAAO,aAAa,EAAE,YAAY,EACtC,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,UAAU,CAAC,CAGrB"}
package/dist/seed.js CHANGED
@@ -47,6 +47,8 @@ export class WorkspaceSeeder {
47
47
  reindexed: 0,
48
48
  errors: [],
49
49
  };
50
+ const gcResult = this.chunkStore.garbageCollectMissingSources({ sourcePathPrefix: workspaceDir });
51
+ result.totalDeleted += gcResult.chunksDeleted;
50
52
  const filesToProcess = this.discoverFiles(workspaceDir, opts);
51
53
  for (const { filePath, collectionDef } of filesToProcess) {
52
54
  // Skip if collection filter provided
@@ -31,6 +31,9 @@ export interface SynthesisResult {
31
31
  topicsSynthesized: number;
32
32
  topicsSkipped: number;
33
33
  knowledgeEntriesWritten: number;
34
+ topicIdsResolved: number;
35
+ topicsWithoutResolvedIds: number;
36
+ topicsWithoutMessages: number;
34
37
  }
35
38
  export declare class TopicSynthesizer {
36
39
  private readonly libraryDb;
@@ -43,6 +46,23 @@ export declare class TopicSynthesizer {
43
46
  * Finds stale topics, synthesizes wiki pages, writes to knowledge table.
44
47
  */
45
48
  tick(agentId: string): SynthesisResult;
49
+ /**
50
+ * Resolve a library topic to message-db topic ids.
51
+ *
52
+ * Library topics use integer ids and aggregate per agent/name. Message DBs
53
+ * use UUID topic ids scoped to sessions. Preserve the legacy direct-id path
54
+ * for older data, then bridge current data by case-insensitive topic name.
55
+ */
56
+ private resolveMessageTopicIds;
57
+ /**
58
+ * Load source messages for a library topic.
59
+ *
60
+ * Primary path uses session topic ids. Fallback path mirrors the background
61
+ * indexer's topic detector because library topics are created from message
62
+ * content, not from SessionTopicMap UUID names.
63
+ */
64
+ private loadTopicMessages;
65
+ private loadMessagesByDetectedTopic;
46
66
  /**
47
67
  * Synthesize a wiki page for a topic from its messages.
48
68
  */
@@ -1 +1 @@
1
- {"version":3,"file":"topic-synthesizer.d.ts","sourceRoot":"","sources":["../src/topic-synthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,QAAA,MAAM,uBAAuB,KAAK,CAAC;AACnC,QAAA,MAAM,sBAAsB,IAAI,CAAC;AACjC,QAAA,MAAM,4BAA4B,IAAI,CAAC;AACvC,QAAA,MAAM,2BAA2B,MAAM,CAAC;AACxC,QAAA,MAAM,uBAAuB,KAAK,CAAC;AACnC,QAAA,MAAM,uBAAuB,IAAI,CAAC;AAClC,QAAA,MAAM,cAAc,KAAK,CAAC;AAC1B,QAAA,MAAM,eAAe,IAAI,CAAC;AAG1B,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,2BAA2B,EAC3B,uBAAuB,EACvB,uBAAuB,EACvB,cAAc,EACd,eAAe,GAChB,CAAC;AAIF,MAAM,WAAW,eAAe;IAC9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,4BAA4B,EAAE,MAAM,CAAC;IACrC,2BAA2B,EAAE,MAAM,CAAC;IACpC,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;CACjC;AA6HD,qBAAa,gBAAgB;IAIzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAL1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;gBAG/B,SAAS,EAAE,YAAY,EACvB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,YAAY,GAAG,IAAI,EACtD,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,YAAA;IAcpD;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe;IAmFtC;;OAEG;IACH,OAAO,CAAC,eAAe;CA+GxB"}
1
+ {"version":3,"file":"topic-synthesizer.d.ts","sourceRoot":"","sources":["../src/topic-synthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,QAAA,MAAM,uBAAuB,KAAK,CAAC;AACnC,QAAA,MAAM,sBAAsB,IAAI,CAAC;AACjC,QAAA,MAAM,4BAA4B,IAAI,CAAC;AACvC,QAAA,MAAM,2BAA2B,MAAM,CAAC;AACxC,QAAA,MAAM,uBAAuB,KAAK,CAAC;AACnC,QAAA,MAAM,uBAAuB,IAAI,CAAC;AAClC,QAAA,MAAM,cAAc,KAAK,CAAC;AAC1B,QAAA,MAAM,eAAe,IAAI,CAAC;AAG1B,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,2BAA2B,EAC3B,uBAAuB,EACvB,uBAAuB,EACvB,cAAc,EACd,eAAe,GAChB,CAAC;AAIF,MAAM,WAAW,eAAe;IAC9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,4BAA4B,EAAE,MAAM,CAAC;IACrC,2BAA2B,EAAE,MAAM,CAAC;IACpC,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,wBAAwB,EAAE,MAAM,CAAC;IACjC,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAiID,qBAAa,gBAAgB;IAIzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAL1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;gBAG/B,SAAS,EAAE,YAAY,EACvB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,YAAY,GAAG,IAAI,EACtD,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,YAAA;IAcpD;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe;IA6FtC;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAkB9B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IA2BzB,OAAO,CAAC,2BAA2B;IAgDnC;;OAEG;IACH,OAAO,CAAC,eAAe;CA+GxB"}
@@ -114,6 +114,9 @@ function parseStoredMessageCount(sourceRef) {
114
114
  const match = sourceRef.match(/:mc:(\d+)$/);
115
115
  return match ? parseInt(match[1], 10) : 0;
116
116
  }
117
+ function escapeLike(value) {
118
+ return value.replace(/[\\%_]/g, match => `\\${match}`);
119
+ }
117
120
  // ─── TopicSynthesizer ───────────────────────────────────────────
118
121
  export class TopicSynthesizer {
119
122
  libraryDb;
@@ -144,6 +147,9 @@ export class TopicSynthesizer {
144
147
  topicsSynthesized: 0,
145
148
  topicsSkipped: 0,
146
149
  knowledgeEntriesWritten: 0,
150
+ topicIdsResolved: 0,
151
+ topicsWithoutResolvedIds: 0,
152
+ topicsWithoutMessages: 0,
147
153
  };
148
154
  const cfg = this.effectiveConfig;
149
155
  const staleThresholdMinutes = cfg.SYNTHESIS_STALE_MINUTES;
@@ -184,17 +190,23 @@ export class TopicSynthesizer {
184
190
  result.topicsSkipped++;
185
191
  continue;
186
192
  }
193
+ const resolvedTopicIds = this.resolveMessageTopicIds(messageDb, topic);
194
+ result.topicIdsResolved += resolvedTopicIds.length;
195
+ if (resolvedTopicIds.length === 0) {
196
+ result.topicsWithoutResolvedIds++;
197
+ result.topicsSkipped++;
198
+ continue;
199
+ }
187
200
  let messages;
188
201
  try {
189
- messages = messageDb.prepare(`
190
- SELECT * FROM messages WHERE topic_id = ? ORDER BY created_at ASC
191
- `).all(String(topic.id));
202
+ messages = this.loadTopicMessages(messageDb, topic, resolvedTopicIds);
192
203
  }
193
204
  catch {
194
205
  result.topicsSkipped++;
195
206
  continue;
196
207
  }
197
208
  if (messages.length === 0) {
209
+ result.topicsWithoutMessages++;
198
210
  result.topicsSkipped++;
199
211
  continue;
200
212
  }
@@ -211,6 +223,104 @@ export class TopicSynthesizer {
211
223
  }
212
224
  return result;
213
225
  }
226
+ /**
227
+ * Resolve a library topic to message-db topic ids.
228
+ *
229
+ * Library topics use integer ids and aggregate per agent/name. Message DBs
230
+ * use UUID topic ids scoped to sessions. Preserve the legacy direct-id path
231
+ * for older data, then bridge current data by case-insensitive topic name.
232
+ */
233
+ resolveMessageTopicIds(messageDb, topic) {
234
+ const ids = new Set([String(topic.id)]);
235
+ try {
236
+ const rows = messageDb.prepare(`
237
+ SELECT id FROM topics WHERE lower(name) = lower(?) ORDER BY last_active_at ASC
238
+ `).all(topic.name);
239
+ for (const row of rows) {
240
+ if (row.id)
241
+ ids.add(String(row.id));
242
+ }
243
+ }
244
+ catch {
245
+ // Older message DBs may not have the per-session topics table. In that
246
+ // case the legacy direct-id fallback above is the only valid resolver.
247
+ }
248
+ return [...ids];
249
+ }
250
+ /**
251
+ * Load source messages for a library topic.
252
+ *
253
+ * Primary path uses session topic ids. Fallback path mirrors the background
254
+ * indexer's topic detector because library topics are created from message
255
+ * content, not from SessionTopicMap UUID names.
256
+ */
257
+ loadTopicMessages(messageDb, topic, resolvedTopicIds) {
258
+ const byId = (() => {
259
+ try {
260
+ const placeholders = resolvedTopicIds.map(() => '?').join(', ');
261
+ return messageDb.prepare(`
262
+ SELECT * FROM messages WHERE topic_id IN (${placeholders}) ORDER BY created_at ASC
263
+ `).all(...resolvedTopicIds);
264
+ }
265
+ catch {
266
+ return [];
267
+ }
268
+ })();
269
+ const byContent = this.loadMessagesByDetectedTopic(messageDb, topic);
270
+ const seen = new Set();
271
+ const merged = [];
272
+ for (const msg of [...byId, ...byContent]) {
273
+ if (seen.has(msg.id))
274
+ continue;
275
+ seen.add(msg.id);
276
+ merged.push(msg);
277
+ }
278
+ return merged.sort((a, b) => String(a.created_at).localeCompare(String(b.created_at)));
279
+ }
280
+ loadMessagesByDetectedTopic(messageDb, topic) {
281
+ const topicName = topic.name.toLowerCase();
282
+ const limit = Math.max(topic.message_count * 3, topic.message_count, this.effectiveConfig.SYNTHESIS_MIN_MESSAGES);
283
+ if (topicName === 'infrastructure') {
284
+ return messageDb.prepare(`
285
+ SELECT * FROM messages
286
+ WHERE text_content IS NOT NULL
287
+ AND (
288
+ lower(text_content) LIKE '%redis%'
289
+ OR lower(text_content) LIKE '%sqlite%'
290
+ OR lower(text_content) LIKE '%database%'
291
+ OR lower(text_content) LIKE '%migration%'
292
+ OR lower(text_content) LIKE '%deployment%'
293
+ OR lower(text_content) LIKE '%docker%'
294
+ OR lower(text_content) LIKE '%nginx%'
295
+ )
296
+ ORDER BY created_at ASC
297
+ LIMIT ?
298
+ `).all(limit);
299
+ }
300
+ if (topicName === 'security') {
301
+ return messageDb.prepare(`
302
+ SELECT * FROM messages
303
+ WHERE text_content IS NOT NULL
304
+ AND (
305
+ lower(text_content) LIKE '%security%'
306
+ OR lower(text_content) LIKE '%auth%'
307
+ OR lower(text_content) LIKE '%permission%'
308
+ OR lower(text_content) LIKE '%access%'
309
+ OR lower(text_content) LIKE '%token%'
310
+ OR lower(text_content) LIKE '%credential%'
311
+ )
312
+ ORDER BY created_at ASC
313
+ LIMIT ?
314
+ `).all(limit);
315
+ }
316
+ return messageDb.prepare(`
317
+ SELECT * FROM messages
318
+ WHERE text_content IS NOT NULL
319
+ AND lower(text_content) LIKE ? ESCAPE '\\'
320
+ ORDER BY created_at ASC
321
+ LIMIT ?
322
+ `).all(`%${escapeLike(topicName)}%`, limit);
323
+ }
214
324
  /**
215
325
  * Synthesize a wiki page for a topic from its messages.
216
326
  */
@@ -1 +1 @@
1
- {"version":3,"file":"trigger-registry.d.ts","sourceRoot":"","sources":["../src/trigger-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,EAiH/C,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,qBAAmB,CAAC;AAIjD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAGrB,CAAC;AAIhB;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,iBAAiB,EAAE,GAC5B,iBAAiB,EAAE,CAMrB;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC"}
1
+ {"version":3,"file":"trigger-registry.d.ts","sourceRoot":"","sources":["../src/trigger-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,EAyH/C,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,qBAAmB,CAAC;AAIjD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAGrB,CAAC;AAIhB;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,iBAAiB,EAAE,GAC5B,iBAAiB,EAAE,CAMrB;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC"}