claude-memory-layer 1.0.10 → 1.0.11

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 (74) hide show
  1. package/dist/cli/index.js +1266 -181
  2. package/dist/cli/index.js.map +4 -4
  3. package/dist/core/index.js +367 -7
  4. package/dist/core/index.js.map +2 -2
  5. package/dist/hooks/post-tool-use.js +598 -40
  6. package/dist/hooks/post-tool-use.js.map +4 -4
  7. package/dist/hooks/session-end.js +486 -49
  8. package/dist/hooks/session-end.js.map +3 -3
  9. package/dist/hooks/session-start.js +474 -22
  10. package/dist/hooks/session-start.js.map +3 -3
  11. package/dist/hooks/stop.js +586 -70
  12. package/dist/hooks/stop.js.map +4 -4
  13. package/dist/hooks/user-prompt-submit.js +537 -27
  14. package/dist/hooks/user-prompt-submit.js.map +4 -4
  15. package/dist/server/api/index.js +938 -39
  16. package/dist/server/api/index.js.map +4 -4
  17. package/dist/server/index.js +947 -48
  18. package/dist/server/index.js.map +4 -4
  19. package/dist/services/memory-service.js +475 -22
  20. package/dist/services/memory-service.js.map +3 -3
  21. package/dist/ui/app.js +1380 -55
  22. package/dist/ui/index.html +311 -148
  23. package/dist/ui/style.css +892 -0
  24. package/docs/OPERATIONS.md +18 -0
  25. package/package.json +8 -2
  26. package/scripts/fix-sync-gap.js +32 -0
  27. package/scripts/heartbeat-memory-orchestrator.sh +28 -0
  28. package/scripts/report-sync-gap.js +26 -0
  29. package/scripts/review-queue-auto-resolve.js +21 -0
  30. package/scripts/sync-gap-auto-heal.sh +17 -0
  31. package/specs/20260207-dashboard-upgrade/context.md +38 -0
  32. package/specs/20260207-dashboard-upgrade/spec.md +96 -0
  33. package/src/cli/index.ts +110 -58
  34. package/src/core/sqlite-event-store.ts +444 -6
  35. package/src/core/sqlite-wrapper.ts +8 -0
  36. package/src/core/turn-state.ts +159 -0
  37. package/src/core/types.ts +23 -8
  38. package/src/core/vector-store.ts +21 -3
  39. package/src/hooks/post-tool-use.ts +68 -23
  40. package/src/hooks/session-end.ts +8 -3
  41. package/src/hooks/stop.ts +96 -25
  42. package/src/hooks/user-prompt-submit.ts +44 -5
  43. package/src/server/api/chat.ts +244 -0
  44. package/src/server/api/citations.ts +3 -3
  45. package/src/server/api/events.ts +30 -5
  46. package/src/server/api/index.ts +7 -1
  47. package/src/server/api/projects.ts +74 -0
  48. package/src/server/api/search.ts +3 -3
  49. package/src/server/api/sessions.ts +3 -3
  50. package/src/server/api/stats.ts +43 -7
  51. package/src/server/api/turns.ts +143 -0
  52. package/src/server/api/utils.ts +46 -0
  53. package/src/services/memory-service.ts +137 -5
  54. package/src/services/session-history-importer.ts +215 -51
  55. package/src/ui/app.js +1380 -55
  56. package/src/ui/index.html +311 -148
  57. package/src/ui/style.css +892 -0
  58. package/.claude/settings.local.json +0 -27
  59. package/.claude-memory/test.sqlite +0 -0
  60. package/.history/package_20260201112328.json +0 -45
  61. package/.history/package_20260201113602.json +0 -45
  62. package/.history/package_20260201113713.json +0 -45
  63. package/.history/package_20260201114110.json +0 -45
  64. package/.history/package_20260201114632.json +0 -46
  65. package/.history/package_20260201133143.json +0 -45
  66. package/.history/package_20260201134319.json +0 -45
  67. package/.history/package_20260201134326.json +0 -45
  68. package/.history/package_20260201134334.json +0 -45
  69. package/.history/package_20260201134912.json +0 -45
  70. package/.history/package_20260201142928.json +0 -46
  71. package/.history/package_20260201192048.json +0 -47
  72. package/.history/package_20260202114053.json +0 -49
  73. package/.history/package_20260202121115.json +0 -49
  74. package/test_access.js +0 -49
@@ -1310,7 +1310,13 @@ var EventStore = class {
1310
1310
 
1311
1311
  // src/core/sqlite-wrapper.ts
1312
1312
  import Database from "better-sqlite3";
1313
+ import * as fs from "fs";
1314
+ import * as nodePath from "path";
1313
1315
  function createSQLiteDatabase(path, options) {
1316
+ const dir = nodePath.dirname(path);
1317
+ if (!fs.existsSync(dir)) {
1318
+ fs.mkdirSync(dir, { recursive: true });
1319
+ }
1314
1320
  const db = new Database(path, {
1315
1321
  readonly: options?.readonly ?? false
1316
1322
  });
@@ -1582,6 +1588,23 @@ var SQLiteEventStore = class {
1582
1588
  updated_at TEXT DEFAULT (datetime('now'))
1583
1589
  );
1584
1590
 
1591
+ -- Memory Helpfulness tracking
1592
+ CREATE TABLE IF NOT EXISTS memory_helpfulness (
1593
+ id TEXT PRIMARY KEY,
1594
+ event_id TEXT NOT NULL,
1595
+ session_id TEXT NOT NULL,
1596
+ retrieval_score REAL DEFAULT 0,
1597
+ query_preview TEXT,
1598
+ session_continued INTEGER DEFAULT 0,
1599
+ prompt_count_after INTEGER DEFAULT 0,
1600
+ tool_success_count INTEGER DEFAULT 0,
1601
+ tool_total_count INTEGER DEFAULT 0,
1602
+ was_reasked INTEGER DEFAULT 0,
1603
+ helpfulness_score REAL DEFAULT 0.5,
1604
+ created_at TEXT DEFAULT (datetime('now')),
1605
+ measured_at TEXT
1606
+ );
1607
+
1585
1608
  -- Sync position tracking (for SQLite -> DuckDB sync)
1586
1609
  CREATE TABLE IF NOT EXISTS sync_positions (
1587
1610
  target_name TEXT PRIMARY KEY,
@@ -1607,6 +1630,9 @@ var SQLiteEventStore = class {
1607
1630
  CREATE INDEX IF NOT EXISTS idx_consolidated_confidence ON consolidated_memories(confidence);
1608
1631
  CREATE INDEX IF NOT EXISTS idx_continuity_created ON continuity_log(created_at);
1609
1632
  CREATE INDEX IF NOT EXISTS idx_embedding_outbox_status ON embedding_outbox(status);
1633
+ CREATE INDEX IF NOT EXISTS idx_helpfulness_event ON memory_helpfulness(event_id);
1634
+ CREATE INDEX IF NOT EXISTS idx_helpfulness_session ON memory_helpfulness(session_id);
1635
+ CREATE INDEX IF NOT EXISTS idx_helpfulness_score ON memory_helpfulness(helpfulness_score DESC);
1610
1636
 
1611
1637
  -- FTS5 Full-Text Search for fast keyword search
1612
1638
  CREATE VIRTUAL TABLE IF NOT EXISTS events_fts USING fts5(
@@ -1650,6 +1676,15 @@ var SQLiteEventStore = class {
1650
1676
  console.error("Error adding last_accessed_at column:", err);
1651
1677
  }
1652
1678
  }
1679
+ if (!columnNames.includes("turn_id")) {
1680
+ try {
1681
+ sqliteExec(this.db, `
1682
+ ALTER TABLE events ADD COLUMN turn_id TEXT;
1683
+ `);
1684
+ } catch (err) {
1685
+ console.error("Error adding turn_id column:", err);
1686
+ }
1687
+ }
1653
1688
  try {
1654
1689
  sqliteExec(this.db, `
1655
1690
  CREATE INDEX IF NOT EXISTS idx_events_access_count ON events(access_count DESC);
@@ -1662,6 +1697,12 @@ var SQLiteEventStore = class {
1662
1697
  `);
1663
1698
  } catch (err) {
1664
1699
  }
1700
+ try {
1701
+ sqliteExec(this.db, `
1702
+ CREATE INDEX IF NOT EXISTS idx_events_turn_id ON events(turn_id);
1703
+ `);
1704
+ } catch (err) {
1705
+ }
1665
1706
  this.initialized = true;
1666
1707
  }
1667
1708
  /**
@@ -1686,9 +1727,11 @@ var SQLiteEventStore = class {
1686
1727
  const id = randomUUID2();
1687
1728
  const timestamp = toSQLiteTimestamp(input.timestamp);
1688
1729
  try {
1730
+ const metadata = input.metadata || {};
1731
+ const turnId = metadata.turnId || null;
1689
1732
  const insertEvent = this.db.prepare(`
1690
- INSERT INTO events (id, event_type, session_id, timestamp, content, canonical_key, dedupe_key, metadata)
1691
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
1733
+ INSERT INTO events (id, event_type, session_id, timestamp, content, canonical_key, dedupe_key, metadata, turn_id)
1734
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
1692
1735
  `);
1693
1736
  const insertDedup = this.db.prepare(`
1694
1737
  INSERT INTO event_dedup (dedupe_key, event_id) VALUES (?, ?)
@@ -1705,7 +1748,8 @@ var SQLiteEventStore = class {
1705
1748
  input.content,
1706
1749
  canonicalKey,
1707
1750
  dedupeKey,
1708
- JSON.stringify(input.metadata || {})
1751
+ JSON.stringify(metadata),
1752
+ turnId
1709
1753
  );
1710
1754
  insertDedup.run(dedupeKey, id);
1711
1755
  insertLevel.run(id);
@@ -2055,11 +2099,11 @@ var SQLiteEventStore = class {
2055
2099
  );
2056
2100
  }
2057
2101
  /**
2058
- * Get most accessed memories
2102
+ * Get most accessed memories (falls back to recent events if none accessed)
2059
2103
  */
2060
2104
  async getMostAccessed(limit = 10) {
2061
2105
  await this.initialize();
2062
- const rows = sqliteAll(
2106
+ let rows = sqliteAll(
2063
2107
  this.db,
2064
2108
  `SELECT * FROM events
2065
2109
  WHERE access_count > 0
@@ -2067,8 +2111,166 @@ var SQLiteEventStore = class {
2067
2111
  LIMIT ?`,
2068
2112
  [limit]
2069
2113
  );
2114
+ if (rows.length === 0) {
2115
+ rows = sqliteAll(
2116
+ this.db,
2117
+ `SELECT * FROM events
2118
+ ORDER BY timestamp DESC
2119
+ LIMIT ?`,
2120
+ [limit]
2121
+ );
2122
+ }
2070
2123
  return rows.map((row) => this.rowToEvent(row));
2071
2124
  }
2125
+ /**
2126
+ * Record a memory retrieval for helpfulness tracking
2127
+ */
2128
+ async recordRetrieval(eventId, sessionId, score, query) {
2129
+ if (this.readOnly)
2130
+ return;
2131
+ await this.initialize();
2132
+ const id = randomUUID2();
2133
+ sqliteRun(
2134
+ this.db,
2135
+ `INSERT INTO memory_helpfulness (id, event_id, session_id, retrieval_score, query_preview, created_at)
2136
+ VALUES (?, ?, ?, ?, ?, datetime('now'))`,
2137
+ [id, eventId, sessionId, score, query.slice(0, 100)]
2138
+ );
2139
+ }
2140
+ /**
2141
+ * Evaluate helpfulness for all retrievals in a session
2142
+ * Called at session end - uses behavioral signals to compute score
2143
+ */
2144
+ async evaluateSessionHelpfulness(sessionId) {
2145
+ if (this.readOnly)
2146
+ return;
2147
+ await this.initialize();
2148
+ const retrievals = sqliteAll(
2149
+ this.db,
2150
+ `SELECT * FROM memory_helpfulness WHERE session_id = ? AND measured_at IS NULL`,
2151
+ [sessionId]
2152
+ );
2153
+ if (retrievals.length === 0)
2154
+ return;
2155
+ const sessionEvents = sqliteAll(
2156
+ this.db,
2157
+ `SELECT * FROM events WHERE session_id = ? ORDER BY timestamp ASC`,
2158
+ [sessionId]
2159
+ );
2160
+ const promptEvents = sessionEvents.filter((e) => e.event_type === "user_prompt");
2161
+ const toolEvents = sessionEvents.filter((e) => e.event_type === "tool_observation");
2162
+ let toolSuccessCount = 0;
2163
+ let toolTotalCount = toolEvents.length;
2164
+ for (const t of toolEvents) {
2165
+ try {
2166
+ const content = JSON.parse(t.content);
2167
+ if (content.success !== false)
2168
+ toolSuccessCount++;
2169
+ } catch {
2170
+ toolSuccessCount++;
2171
+ }
2172
+ }
2173
+ const toolSuccessRatio = toolTotalCount > 0 ? toolSuccessCount / toolTotalCount : 0.5;
2174
+ for (const retrieval of retrievals) {
2175
+ const retrievalTime = retrieval.created_at;
2176
+ const eventsAfter = sessionEvents.filter((e) => e.timestamp > retrievalTime);
2177
+ const sessionContinued = eventsAfter.length > 0 ? 1 : 0;
2178
+ const promptsAfter = promptEvents.filter((e) => e.timestamp > retrievalTime);
2179
+ const promptCountAfter = promptsAfter.length;
2180
+ const queryWords = new Set((retrieval.query_preview || "").toLowerCase().split(/\s+/).filter((w) => w.length > 2));
2181
+ let wasReasked = 0;
2182
+ for (const p of promptsAfter) {
2183
+ const pWords = new Set(p.content.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
2184
+ let overlap = 0;
2185
+ for (const w of queryWords) {
2186
+ if (pWords.has(w))
2187
+ overlap++;
2188
+ }
2189
+ if (queryWords.size > 0 && overlap / queryWords.size > 0.5) {
2190
+ wasReasked = 1;
2191
+ break;
2192
+ }
2193
+ }
2194
+ const retrievalScore = retrieval.retrieval_score || 0;
2195
+ const helpfulnessScore = 0.3 * Math.min(retrievalScore, 1) + 0.25 * (sessionContinued ? 1 : 0) + 0.25 * toolSuccessRatio + 0.2 * (wasReasked ? 0 : 1);
2196
+ sqliteRun(
2197
+ this.db,
2198
+ `UPDATE memory_helpfulness
2199
+ SET session_continued = ?, prompt_count_after = ?,
2200
+ tool_success_count = ?, tool_total_count = ?,
2201
+ was_reasked = ?, helpfulness_score = ?,
2202
+ measured_at = datetime('now')
2203
+ WHERE id = ?`,
2204
+ [
2205
+ sessionContinued,
2206
+ promptCountAfter,
2207
+ toolSuccessCount,
2208
+ toolTotalCount,
2209
+ wasReasked,
2210
+ helpfulnessScore,
2211
+ retrieval.id
2212
+ ]
2213
+ );
2214
+ }
2215
+ }
2216
+ /**
2217
+ * Get most helpful memories ranked by helpfulness score
2218
+ */
2219
+ async getHelpfulMemories(limit = 10) {
2220
+ await this.initialize();
2221
+ const rows = sqliteAll(
2222
+ this.db,
2223
+ `SELECT
2224
+ mh.event_id,
2225
+ AVG(mh.helpfulness_score) as avg_score,
2226
+ COUNT(*) as eval_count,
2227
+ e.content,
2228
+ e.access_count
2229
+ FROM memory_helpfulness mh
2230
+ JOIN events e ON e.id = mh.event_id
2231
+ WHERE mh.measured_at IS NOT NULL
2232
+ GROUP BY mh.event_id
2233
+ ORDER BY avg_score DESC
2234
+ LIMIT ?`,
2235
+ [limit]
2236
+ );
2237
+ return rows.map((r) => ({
2238
+ eventId: r.event_id,
2239
+ summary: r.content.substring(0, 200) + (r.content.length > 200 ? "..." : ""),
2240
+ helpfulnessScore: Math.round(r.avg_score * 100) / 100,
2241
+ accessCount: r.access_count || 0,
2242
+ evaluationCount: r.eval_count
2243
+ }));
2244
+ }
2245
+ /**
2246
+ * Get helpfulness statistics for dashboard
2247
+ */
2248
+ async getHelpfulnessStats() {
2249
+ await this.initialize();
2250
+ const stats = sqliteGet(
2251
+ this.db,
2252
+ `SELECT
2253
+ AVG(helpfulness_score) as avg_score,
2254
+ COUNT(*) as total_evaluated,
2255
+ SUM(CASE WHEN helpfulness_score >= 0.7 THEN 1 ELSE 0 END) as helpful,
2256
+ SUM(CASE WHEN helpfulness_score >= 0.4 AND helpfulness_score < 0.7 THEN 1 ELSE 0 END) as neutral,
2257
+ SUM(CASE WHEN helpfulness_score < 0.4 THEN 1 ELSE 0 END) as unhelpful
2258
+ FROM memory_helpfulness
2259
+ WHERE measured_at IS NOT NULL`
2260
+ );
2261
+ const totalRow = sqliteGet(
2262
+ this.db,
2263
+ `SELECT COUNT(*) as total FROM memory_helpfulness`
2264
+ );
2265
+ return {
2266
+ avgScore: Math.round((stats?.avg_score || 0) * 100) / 100,
2267
+ totalEvaluated: stats?.total_evaluated || 0,
2268
+ totalRetrievals: totalRow?.total || 0,
2269
+ helpful: stats?.helpful || 0,
2270
+ neutral: stats?.neutral || 0,
2271
+ unhelpful: stats?.unhelpful || 0
2272
+ };
2273
+ }
2072
2274
  /**
2073
2275
  * Fast keyword search using FTS5
2074
2276
  * Returns events matching the search query, ranked by relevance
@@ -2137,6 +2339,143 @@ var SQLiteEventStore = class {
2137
2339
  async close() {
2138
2340
  sqliteClose(this.db);
2139
2341
  }
2342
+ /**
2343
+ * Get events grouped by turn_id for a session
2344
+ * Returns turns ordered by first event timestamp (newest first)
2345
+ */
2346
+ async getSessionTurns(sessionId, options) {
2347
+ await this.initialize();
2348
+ const limit = options?.limit || 20;
2349
+ const offset = options?.offset || 0;
2350
+ const turnRows = sqliteAll(
2351
+ this.db,
2352
+ `SELECT turn_id, MIN(timestamp) as min_ts
2353
+ FROM events
2354
+ WHERE session_id = ? AND turn_id IS NOT NULL
2355
+ GROUP BY turn_id
2356
+ ORDER BY min_ts DESC
2357
+ LIMIT ? OFFSET ?`,
2358
+ [sessionId, limit, offset]
2359
+ );
2360
+ const turns = [];
2361
+ for (const turnRow of turnRows) {
2362
+ const events = await this.getEventsByTurn(turnRow.turn_id);
2363
+ const promptEvent = events.find((e) => e.eventType === "user_prompt");
2364
+ const toolEvents = events.filter((e) => e.eventType === "tool_observation");
2365
+ const hasResponse = events.some((e) => e.eventType === "agent_response");
2366
+ turns.push({
2367
+ turnId: turnRow.turn_id,
2368
+ events,
2369
+ startedAt: toDateFromSQLite(turnRow.min_ts),
2370
+ promptPreview: promptEvent ? promptEvent.content.slice(0, 200) + (promptEvent.content.length > 200 ? "..." : "") : "(no prompt)",
2371
+ eventCount: events.length,
2372
+ toolCount: toolEvents.length,
2373
+ hasResponse
2374
+ });
2375
+ }
2376
+ return turns;
2377
+ }
2378
+ /**
2379
+ * Get all events for a specific turn_id
2380
+ */
2381
+ async getEventsByTurn(turnId) {
2382
+ await this.initialize();
2383
+ const rows = sqliteAll(
2384
+ this.db,
2385
+ `SELECT * FROM events WHERE turn_id = ? ORDER BY timestamp ASC`,
2386
+ [turnId]
2387
+ );
2388
+ return rows.map(this.rowToEvent);
2389
+ }
2390
+ /**
2391
+ * Count total turns for a session
2392
+ */
2393
+ async countSessionTurns(sessionId) {
2394
+ await this.initialize();
2395
+ const row = sqliteGet(
2396
+ this.db,
2397
+ `SELECT COUNT(DISTINCT turn_id) as count
2398
+ FROM events
2399
+ WHERE session_id = ? AND turn_id IS NOT NULL`,
2400
+ [sessionId]
2401
+ );
2402
+ return row?.count || 0;
2403
+ }
2404
+ /**
2405
+ * Migrate existing events: backfill turn_id for events that have turnId in metadata
2406
+ * but no turn_id column value (for events stored before this migration)
2407
+ */
2408
+ async backfillTurnIds() {
2409
+ await this.initialize();
2410
+ const rows = sqliteAll(
2411
+ this.db,
2412
+ `SELECT id, metadata FROM events
2413
+ WHERE turn_id IS NULL AND metadata IS NOT NULL AND metadata LIKE '%turnId%'`
2414
+ );
2415
+ let updated = 0;
2416
+ for (const row of rows) {
2417
+ try {
2418
+ const metadata = JSON.parse(row.metadata);
2419
+ if (metadata.turnId) {
2420
+ sqliteRun(
2421
+ this.db,
2422
+ `UPDATE events SET turn_id = ? WHERE id = ?`,
2423
+ [metadata.turnId, row.id]
2424
+ );
2425
+ updated++;
2426
+ }
2427
+ } catch {
2428
+ }
2429
+ }
2430
+ return updated;
2431
+ }
2432
+ /**
2433
+ * Delete all events for a session (for force reimport)
2434
+ */
2435
+ async deleteSessionEvents(sessionId) {
2436
+ await this.initialize();
2437
+ const events = sqliteAll(
2438
+ this.db,
2439
+ `SELECT id FROM events WHERE session_id = ?`,
2440
+ [sessionId]
2441
+ );
2442
+ if (events.length === 0)
2443
+ return 0;
2444
+ const eventIds = events.map((e) => e.id);
2445
+ const placeholders = eventIds.map(() => "?").join(",");
2446
+ const ftsTriggersDropped = [];
2447
+ for (const triggerName of ["events_fts_delete", "events_fts_update", "events_fts_insert"]) {
2448
+ try {
2449
+ sqliteRun(this.db, `DROP TRIGGER IF EXISTS ${triggerName}`);
2450
+ ftsTriggersDropped.push(triggerName);
2451
+ } catch {
2452
+ }
2453
+ }
2454
+ for (const table of ["event_dedup", "memory_levels", "embedding_queue", "embedding_outbox", "vector_outbox"]) {
2455
+ try {
2456
+ sqliteRun(this.db, `DELETE FROM ${table} WHERE event_id IN (${placeholders})`, eventIds);
2457
+ } catch {
2458
+ }
2459
+ }
2460
+ const result = sqliteRun(this.db, `DELETE FROM events WHERE session_id = ?`, [sessionId]);
2461
+ if (ftsTriggersDropped.length > 0) {
2462
+ try {
2463
+ sqliteRun(this.db, `INSERT INTO events_fts(events_fts) VALUES('rebuild')`);
2464
+ sqliteRun(this.db, `CREATE TRIGGER IF NOT EXISTS events_fts_insert AFTER INSERT ON events BEGIN
2465
+ INSERT INTO events_fts(rowid, content) VALUES (NEW.rowid, NEW.content);
2466
+ END`);
2467
+ sqliteRun(this.db, `CREATE TRIGGER IF NOT EXISTS events_fts_delete AFTER DELETE ON events BEGIN
2468
+ INSERT INTO events_fts(events_fts, rowid, content) VALUES('delete', OLD.rowid, OLD.content);
2469
+ END`);
2470
+ sqliteRun(this.db, `CREATE TRIGGER IF NOT EXISTS events_fts_update AFTER UPDATE ON events BEGIN
2471
+ INSERT INTO events_fts(events_fts, rowid, content) VALUES('delete', OLD.rowid, OLD.content);
2472
+ INSERT INTO events_fts(rowid, content) VALUES (NEW.rowid, NEW.content);
2473
+ END`);
2474
+ } catch {
2475
+ }
2476
+ }
2477
+ return result.changes || 0;
2478
+ }
2140
2479
  /**
2141
2480
  * Convert database row to MemoryEvent
2142
2481
  */
@@ -2157,6 +2496,9 @@ var SQLiteEventStore = class {
2157
2496
  if (row.last_accessed_at !== void 0) {
2158
2497
  event.last_accessed_at = row.last_accessed_at;
2159
2498
  }
2499
+ if (row.turn_id !== void 0 && row.turn_id !== null) {
2500
+ event.turn_id = row.turn_id;
2501
+ }
2160
2502
  return event;
2161
2503
  }
2162
2504
  };
@@ -2886,7 +3228,16 @@ var VectorStore = class {
2886
3228
  metadata: JSON.stringify(record.metadata || {})
2887
3229
  };
2888
3230
  if (!this.table) {
2889
- this.table = await this.db.createTable(this.tableName, [data]);
3231
+ try {
3232
+ this.table = await this.db.createTable(this.tableName, [data]);
3233
+ } catch (e) {
3234
+ if (e?.message?.includes("already exists")) {
3235
+ this.table = await this.db.openTable(this.tableName);
3236
+ await this.table.add([data]);
3237
+ } else {
3238
+ throw e;
3239
+ }
3240
+ }
2890
3241
  } else {
2891
3242
  await this.table.add([data]);
2892
3243
  }
@@ -2912,7 +3263,16 @@ var VectorStore = class {
2912
3263
  metadata: JSON.stringify(record.metadata || {})
2913
3264
  }));
2914
3265
  if (!this.table) {
2915
- this.table = await this.db.createTable(this.tableName, data);
3266
+ try {
3267
+ this.table = await this.db.createTable(this.tableName, data);
3268
+ } catch (e) {
3269
+ if (e?.message?.includes("already exists")) {
3270
+ this.table = await this.db.openTable(this.tableName);
3271
+ await this.table.add(data);
3272
+ } else {
3273
+ throw e;
3274
+ }
3275
+ }
2916
3276
  } else {
2917
3277
  await this.table.add(data);
2918
3278
  }