dsh-tdai-memory 0.3.1 → 0.3.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.
@@ -308,11 +308,11 @@ export class VectorStore {
308
308
  */
309
309
  initSchema(providerInfo) {
310
310
  // Tracks which provider/model/dimensions were used to generate vectors.
311
- this.db.exec(`
312
- CREATE TABLE IF NOT EXISTS embedding_meta (
313
- key TEXT PRIMARY KEY,
314
- value TEXT NOT NULL
315
- )
311
+ this.db.exec(`
312
+ CREATE TABLE IF NOT EXISTS embedding_meta (
313
+ key TEXT PRIMARY KEY,
314
+ value TEXT NOT NULL
315
+ )
316
316
  `);
317
317
  // Detect whether re-index is needed
318
318
  let needsReindex = false;
@@ -369,22 +369,22 @@ export class VectorStore {
369
369
  }
370
370
  // ── L1 schema ──────────────────────────────────
371
371
  // Metadata table
372
- this.db.exec(`
373
- CREATE TABLE IF NOT EXISTS l1_records (
374
- record_id TEXT PRIMARY KEY,
375
- content TEXT NOT NULL,
376
- type TEXT DEFAULT '',
377
- priority INTEGER DEFAULT 50,
378
- scene_name TEXT DEFAULT '',
379
- session_key TEXT DEFAULT '',
380
- session_id TEXT DEFAULT '',
381
- timestamp_str TEXT DEFAULT '',
382
- timestamp_start TEXT DEFAULT '',
383
- timestamp_end TEXT DEFAULT '',
384
- created_time TEXT DEFAULT '',
385
- updated_time TEXT DEFAULT '',
386
- metadata_json TEXT DEFAULT '{}'
387
- )
372
+ this.db.exec(`
373
+ CREATE TABLE IF NOT EXISTS l1_records (
374
+ record_id TEXT PRIMARY KEY,
375
+ content TEXT NOT NULL,
376
+ type TEXT DEFAULT '',
377
+ priority INTEGER DEFAULT 50,
378
+ scene_name TEXT DEFAULT '',
379
+ session_key TEXT DEFAULT '',
380
+ session_id TEXT DEFAULT '',
381
+ timestamp_str TEXT DEFAULT '',
382
+ timestamp_start TEXT DEFAULT '',
383
+ timestamp_end TEXT DEFAULT '',
384
+ created_time TEXT DEFAULT '',
385
+ updated_time TEXT DEFAULT '',
386
+ metadata_json TEXT DEFAULT '{}'
387
+ )
388
388
  `);
389
389
  // Indexes for common queries
390
390
  this.db.exec("CREATE INDEX IF NOT EXISTS idx_l1_type ON l1_records(type)");
@@ -401,63 +401,63 @@ export class VectorStore {
401
401
  // When provider="none", dimensions=0 and vec0 tables are deferred until a
402
402
  // real embedding provider is configured.
403
403
  if (this.dimensions > 0) {
404
- this.db.exec(`
405
- CREATE VIRTUAL TABLE IF NOT EXISTS l1_vec USING vec0(
406
- record_id TEXT PRIMARY KEY,
407
- embedding float[${this.dimensions}] distance_metric=cosine,
408
- updated_time TEXT DEFAULT ''
409
- )
404
+ this.db.exec(`
405
+ CREATE VIRTUAL TABLE IF NOT EXISTS l1_vec USING vec0(
406
+ record_id TEXT PRIMARY KEY,
407
+ embedding float[${this.dimensions}] distance_metric=cosine,
408
+ updated_time TEXT DEFAULT ''
409
+ )
410
410
  `);
411
411
  }
412
412
  // Prepare statements for reuse
413
- this.stmtUpsertMeta = this.db.prepare(`
414
- INSERT INTO l1_records (
415
- record_id, content, type, priority, scene_name, session_key, session_id,
416
- timestamp_str, timestamp_start, timestamp_end,
417
- created_time, updated_time, metadata_json
418
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
419
- ON CONFLICT(record_id) DO UPDATE SET
420
- content=excluded.content,
421
- type=excluded.type,
422
- priority=excluded.priority,
423
- scene_name=excluded.scene_name,
424
- timestamp_str=excluded.timestamp_str,
425
- timestamp_start=excluded.timestamp_start,
426
- timestamp_end=excluded.timestamp_end,
427
- updated_time=excluded.updated_time,
428
- metadata_json=excluded.metadata_json
413
+ this.stmtUpsertMeta = this.db.prepare(`
414
+ INSERT INTO l1_records (
415
+ record_id, content, type, priority, scene_name, session_key, session_id,
416
+ timestamp_str, timestamp_start, timestamp_end,
417
+ created_time, updated_time, metadata_json
418
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
419
+ ON CONFLICT(record_id) DO UPDATE SET
420
+ content=excluded.content,
421
+ type=excluded.type,
422
+ priority=excluded.priority,
423
+ scene_name=excluded.scene_name,
424
+ timestamp_str=excluded.timestamp_str,
425
+ timestamp_start=excluded.timestamp_start,
426
+ timestamp_end=excluded.timestamp_end,
427
+ updated_time=excluded.updated_time,
428
+ metadata_json=excluded.metadata_json
429
429
  `);
430
430
  if (this.dimensions > 0) {
431
431
  this.stmtDeleteVec = this.db.prepare("DELETE FROM l1_vec WHERE record_id = ?");
432
432
  this.stmtInsertVec = this.db.prepare("INSERT INTO l1_vec (record_id, embedding, updated_time) VALUES (?, ?, ?)");
433
433
  }
434
434
  this.stmtDeleteMeta = this.db.prepare("DELETE FROM l1_records WHERE record_id = ?");
435
- this.stmtGetMeta = this.db.prepare(`
436
- SELECT content, type, priority, scene_name, session_key, session_id,
437
- timestamp_str, timestamp_start, timestamp_end, metadata_json
438
- FROM l1_records WHERE record_id = ?
435
+ this.stmtGetMeta = this.db.prepare(`
436
+ SELECT content, type, priority, scene_name, session_key, session_id,
437
+ timestamp_str, timestamp_start, timestamp_end, metadata_json
438
+ FROM l1_records WHERE record_id = ?
439
439
  `);
440
440
  if (this.dimensions > 0) {
441
- this.stmtSearchVec = this.db.prepare(`
442
- SELECT record_id, distance
443
- FROM l1_vec
444
- WHERE embedding MATCH ?
445
- AND k = ?
446
- ORDER BY distance
441
+ this.stmtSearchVec = this.db.prepare(`
442
+ SELECT record_id, distance
443
+ FROM l1_vec
444
+ WHERE embedding MATCH ?
445
+ AND k = ?
446
+ ORDER BY distance
447
447
  `);
448
448
  }
449
449
  // ── L0 schema ──────────────────────────────────
450
450
  // L0 metadata table: stores individual messages for vector search
451
- this.db.exec(`
452
- CREATE TABLE IF NOT EXISTS l0_conversations (
453
- record_id TEXT PRIMARY KEY,
454
- session_key TEXT NOT NULL,
455
- session_id TEXT DEFAULT '',
456
- role TEXT NOT NULL DEFAULT '',
457
- message_text TEXT NOT NULL,
458
- recorded_at TEXT DEFAULT '',
459
- timestamp INTEGER DEFAULT 0
460
- )
451
+ this.db.exec(`
452
+ CREATE TABLE IF NOT EXISTS l0_conversations (
453
+ record_id TEXT PRIMARY KEY,
454
+ session_key TEXT NOT NULL,
455
+ session_id TEXT DEFAULT '',
456
+ role TEXT NOT NULL DEFAULT '',
457
+ message_text TEXT NOT NULL,
458
+ recorded_at TEXT DEFAULT '',
459
+ timestamp INTEGER DEFAULT 0
460
+ )
461
461
  `);
462
462
  // Migration: add timestamp column if missing (existing DBs pre-v3.x)
463
463
  try {
@@ -474,65 +474,65 @@ export class VectorStore {
474
474
  this.db.exec("CREATE INDEX IF NOT EXISTS idx_l0_timestamp ON l0_conversations(timestamp)");
475
475
  // L0 vector virtual table (cosine distance, same dimensions as L1) — deferred when dimensions=0
476
476
  if (this.dimensions > 0) {
477
- this.db.exec(`
478
- CREATE VIRTUAL TABLE IF NOT EXISTS l0_vec USING vec0(
479
- record_id TEXT PRIMARY KEY,
480
- embedding float[${this.dimensions}] distance_metric=cosine,
481
- recorded_at TEXT DEFAULT ''
482
- )
477
+ this.db.exec(`
478
+ CREATE VIRTUAL TABLE IF NOT EXISTS l0_vec USING vec0(
479
+ record_id TEXT PRIMARY KEY,
480
+ embedding float[${this.dimensions}] distance_metric=cosine,
481
+ recorded_at TEXT DEFAULT ''
482
+ )
483
483
  `);
484
484
  }
485
485
  // L0 prepared statements
486
- this.stmtL0UpsertMeta = this.db.prepare(`
487
- INSERT INTO l0_conversations (
488
- record_id, session_key, session_id, role, message_text, recorded_at, timestamp
489
- ) VALUES (?, ?, ?, ?, ?, ?, ?)
490
- ON CONFLICT(record_id) DO UPDATE SET
491
- message_text=excluded.message_text,
492
- recorded_at=excluded.recorded_at,
493
- timestamp=excluded.timestamp
486
+ this.stmtL0UpsertMeta = this.db.prepare(`
487
+ INSERT INTO l0_conversations (
488
+ record_id, session_key, session_id, role, message_text, recorded_at, timestamp
489
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
490
+ ON CONFLICT(record_id) DO UPDATE SET
491
+ message_text=excluded.message_text,
492
+ recorded_at=excluded.recorded_at,
493
+ timestamp=excluded.timestamp
494
494
  `);
495
495
  if (this.dimensions > 0) {
496
496
  this.stmtL0DeleteVec = this.db.prepare("DELETE FROM l0_vec WHERE record_id = ?");
497
497
  this.stmtL0InsertVec = this.db.prepare("INSERT INTO l0_vec (record_id, embedding, recorded_at) VALUES (?, ?, ?)");
498
498
  }
499
499
  this.stmtL0DeleteMeta = this.db.prepare("DELETE FROM l0_conversations WHERE record_id = ?");
500
- this.stmtL0GetMeta = this.db.prepare(`
501
- SELECT session_key, session_id, role, message_text, recorded_at, timestamp
502
- FROM l0_conversations WHERE record_id = ?
500
+ this.stmtL0GetMeta = this.db.prepare(`
501
+ SELECT session_key, session_id, role, message_text, recorded_at, timestamp
502
+ FROM l0_conversations WHERE record_id = ?
503
503
  `);
504
504
  if (this.dimensions > 0) {
505
- this.stmtL0SearchVec = this.db.prepare(`
506
- SELECT record_id, distance
507
- FROM l0_vec
508
- WHERE embedding MATCH ?
509
- AND k = ?
510
- ORDER BY distance
505
+ this.stmtL0SearchVec = this.db.prepare(`
506
+ SELECT record_id, distance
507
+ FROM l0_vec
508
+ WHERE embedding MATCH ?
509
+ AND k = ?
510
+ ORDER BY distance
511
511
  `);
512
512
  }
513
513
  // L0 query statements for L1 runner (newest-first + LIMIT to bound memory)
514
514
  // Sort/filter by recorded_at (write time) instead of timestamp (conversation time)
515
515
  // because L1 cursor uses recorded_at semantics. ISO 8601 string comparison preserves time order.
516
- this.stmtL0QueryAll = this.db.prepare(`
517
- SELECT record_id, session_key, session_id, role, message_text, recorded_at, timestamp
518
- FROM l0_conversations
519
- WHERE session_key = ?
520
- ORDER BY recorded_at DESC
521
- LIMIT ?
516
+ this.stmtL0QueryAll = this.db.prepare(`
517
+ SELECT record_id, session_key, session_id, role, message_text, recorded_at, timestamp
518
+ FROM l0_conversations
519
+ WHERE session_key = ?
520
+ ORDER BY recorded_at DESC
521
+ LIMIT ?
522
522
  `);
523
- this.stmtL0QueryAfter = this.db.prepare(`
524
- SELECT record_id, session_key, session_id, role, message_text, recorded_at, timestamp
525
- FROM l0_conversations
526
- WHERE session_key = ? AND recorded_at > ?
527
- ORDER BY recorded_at DESC
528
- LIMIT ?
523
+ this.stmtL0QueryAfter = this.db.prepare(`
524
+ SELECT record_id, session_key, session_id, role, message_text, recorded_at, timestamp
525
+ FROM l0_conversations
526
+ WHERE session_key = ? AND recorded_at > ?
527
+ ORDER BY recorded_at DESC
528
+ LIMIT ?
529
529
  `);
530
- this.stmtL0QueryMigrationCursor = this.db.prepare(`
531
- SELECT record_id, session_key, session_id, role, message_text, recorded_at, timestamp
532
- FROM l0_conversations
533
- WHERE record_id > ?
534
- ORDER BY record_id ASC
535
- LIMIT ?
530
+ this.stmtL0QueryMigrationCursor = this.db.prepare(`
531
+ SELECT record_id, session_key, session_id, role, message_text, recorded_at, timestamp
532
+ FROM l0_conversations
533
+ WHERE record_id > ?
534
+ ORDER BY record_id ASC
535
+ LIMIT ?
536
536
  `);
537
537
  // ── FTS5 tables (best-effort — gracefully degrade if fts5 is not compiled in) ──
538
538
  // Schema v2: `content` column stores jieba-segmented text (for indexing),
@@ -546,65 +546,65 @@ export class VectorStore {
546
546
  // drop and recreate. The data will be repopulated by `rebuildFtsIndex()`.
547
547
  const needsFtsRebuild = this.migrateFtsTablesIfNeeded();
548
548
  // L1 FTS5 virtual table (v2 schema)
549
- this.db.exec(`
550
- CREATE VIRTUAL TABLE IF NOT EXISTS l1_fts USING fts5(
551
- content,
552
- content_original UNINDEXED,
553
- record_id UNINDEXED,
554
- type UNINDEXED,
555
- priority UNINDEXED,
556
- scene_name UNINDEXED,
557
- session_key UNINDEXED,
558
- session_id UNINDEXED,
559
- timestamp_str UNINDEXED,
560
- timestamp_start UNINDEXED,
561
- timestamp_end UNINDEXED,
562
- metadata_json UNINDEXED
563
- )
549
+ this.db.exec(`
550
+ CREATE VIRTUAL TABLE IF NOT EXISTS l1_fts USING fts5(
551
+ content,
552
+ content_original UNINDEXED,
553
+ record_id UNINDEXED,
554
+ type UNINDEXED,
555
+ priority UNINDEXED,
556
+ scene_name UNINDEXED,
557
+ session_key UNINDEXED,
558
+ session_id UNINDEXED,
559
+ timestamp_str UNINDEXED,
560
+ timestamp_start UNINDEXED,
561
+ timestamp_end UNINDEXED,
562
+ metadata_json UNINDEXED
563
+ )
564
564
  `);
565
565
  // L0 FTS5 virtual table (v2 schema)
566
- this.db.exec(`
567
- CREATE VIRTUAL TABLE IF NOT EXISTS l0_fts USING fts5(
568
- message_text,
569
- message_text_original UNINDEXED,
570
- record_id UNINDEXED,
571
- session_key UNINDEXED,
572
- session_id UNINDEXED,
573
- role UNINDEXED,
574
- recorded_at UNINDEXED,
575
- timestamp UNINDEXED
576
- )
566
+ this.db.exec(`
567
+ CREATE VIRTUAL TABLE IF NOT EXISTS l0_fts USING fts5(
568
+ message_text,
569
+ message_text_original UNINDEXED,
570
+ record_id UNINDEXED,
571
+ session_key UNINDEXED,
572
+ session_id UNINDEXED,
573
+ role UNINDEXED,
574
+ recorded_at UNINDEXED,
575
+ timestamp UNINDEXED
576
+ )
577
577
  `);
578
578
  // L1 FTS prepared statements
579
- this.stmtL1FtsInsert = this.db.prepare(`
580
- INSERT INTO l1_fts (content, content_original, record_id, type, priority, scene_name,
581
- session_key, session_id, timestamp_str, timestamp_start, timestamp_end, metadata_json)
582
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
579
+ this.stmtL1FtsInsert = this.db.prepare(`
580
+ INSERT INTO l1_fts (content, content_original, record_id, type, priority, scene_name,
581
+ session_key, session_id, timestamp_str, timestamp_start, timestamp_end, metadata_json)
582
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
583
583
  `);
584
584
  this.stmtL1FtsDelete = this.db.prepare("DELETE FROM l1_fts WHERE record_id = ?");
585
- this.stmtL1FtsSearch = this.db.prepare(`
586
- SELECT record_id, content_original AS content, type, priority, scene_name,
587
- session_key, session_id, timestamp_str, timestamp_start, timestamp_end,
588
- metadata_json,
589
- bm25(l1_fts) AS rank
590
- FROM l1_fts
591
- WHERE l1_fts MATCH ?
592
- ORDER BY rank ASC
593
- LIMIT ?
585
+ this.stmtL1FtsSearch = this.db.prepare(`
586
+ SELECT record_id, content_original AS content, type, priority, scene_name,
587
+ session_key, session_id, timestamp_str, timestamp_start, timestamp_end,
588
+ metadata_json,
589
+ bm25(l1_fts) AS rank
590
+ FROM l1_fts
591
+ WHERE l1_fts MATCH ?
592
+ ORDER BY rank ASC
593
+ LIMIT ?
594
594
  `);
595
595
  // L0 FTS prepared statements
596
- this.stmtL0FtsInsert = this.db.prepare(`
597
- INSERT INTO l0_fts (message_text, message_text_original, record_id, session_key, session_id, role, recorded_at, timestamp)
598
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
596
+ this.stmtL0FtsInsert = this.db.prepare(`
597
+ INSERT INTO l0_fts (message_text, message_text_original, record_id, session_key, session_id, role, recorded_at, timestamp)
598
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
599
599
  `);
600
600
  this.stmtL0FtsDelete = this.db.prepare("DELETE FROM l0_fts WHERE record_id = ?");
601
- this.stmtL0FtsSearch = this.db.prepare(`
602
- SELECT record_id, message_text_original AS message_text, session_key, session_id, role, recorded_at, timestamp,
603
- bm25(l0_fts) AS rank
604
- FROM l0_fts
605
- WHERE l0_fts MATCH ?
606
- ORDER BY rank ASC
607
- LIMIT ?
601
+ this.stmtL0FtsSearch = this.db.prepare(`
602
+ SELECT record_id, message_text_original AS message_text, session_key, session_id, role, recorded_at, timestamp,
603
+ bm25(l0_fts) AS rank
604
+ FROM l0_fts
605
+ WHERE l0_fts MATCH ?
606
+ ORDER BY rank ASC
607
+ LIMIT ?
608
608
  `);
609
609
  this.ftsAvailable = true;
610
610
  this.logger?.debug?.(`${TAG} FTS5 tables initialized (l1_fts, l0_fts) [schema v2 — jieba segmented]`);
@@ -630,43 +630,43 @@ export class VectorStore {
630
630
  // Mark vec0 tables as ready only when they were actually created
631
631
  this.vecTablesReady = this.dimensions > 0;
632
632
  // L1 query statements (for l1-reader)
633
- const l1QueryCols = `record_id, content, type, priority, scene_name, session_key, session_id,
634
- timestamp_str, timestamp_start, timestamp_end,
633
+ const l1QueryCols = `record_id, content, type, priority, scene_name, session_key, session_id,
634
+ timestamp_str, timestamp_start, timestamp_end,
635
635
  created_time, updated_time, metadata_json`;
636
- this.stmtQueryBySessionId = this.db.prepare(`
637
- SELECT ${l1QueryCols} FROM l1_records
638
- WHERE session_id = ?
639
- ORDER BY updated_time ASC
636
+ this.stmtQueryBySessionId = this.db.prepare(`
637
+ SELECT ${l1QueryCols} FROM l1_records
638
+ WHERE session_id = ?
639
+ ORDER BY updated_time ASC
640
640
  `);
641
- this.stmtQueryBySessionIdSince = this.db.prepare(`
642
- SELECT ${l1QueryCols} FROM l1_records
643
- WHERE session_id = ? AND updated_time > ?
644
- ORDER BY updated_time ASC
641
+ this.stmtQueryBySessionIdSince = this.db.prepare(`
642
+ SELECT ${l1QueryCols} FROM l1_records
643
+ WHERE session_id = ? AND updated_time > ?
644
+ ORDER BY updated_time ASC
645
645
  `);
646
- this.stmtQueryBySessionKey = this.db.prepare(`
647
- SELECT ${l1QueryCols} FROM l1_records
648
- WHERE session_key = ?
649
- ORDER BY updated_time ASC
646
+ this.stmtQueryBySessionKey = this.db.prepare(`
647
+ SELECT ${l1QueryCols} FROM l1_records
648
+ WHERE session_key = ?
649
+ ORDER BY updated_time ASC
650
650
  `);
651
- this.stmtQueryBySessionKeySince = this.db.prepare(`
652
- SELECT ${l1QueryCols} FROM l1_records
653
- WHERE session_key = ? AND updated_time > ?
654
- ORDER BY updated_time ASC
651
+ this.stmtQueryBySessionKeySince = this.db.prepare(`
652
+ SELECT ${l1QueryCols} FROM l1_records
653
+ WHERE session_key = ? AND updated_time > ?
654
+ ORDER BY updated_time ASC
655
655
  `);
656
- this.stmtQueryAll = this.db.prepare(`
657
- SELECT ${l1QueryCols} FROM l1_records
658
- ORDER BY updated_time ASC
656
+ this.stmtQueryAll = this.db.prepare(`
657
+ SELECT ${l1QueryCols} FROM l1_records
658
+ ORDER BY updated_time ASC
659
659
  `);
660
- this.stmtQueryAllSince = this.db.prepare(`
661
- SELECT ${l1QueryCols} FROM l1_records
662
- WHERE updated_time > ?
663
- ORDER BY updated_time ASC
660
+ this.stmtQueryAllSince = this.db.prepare(`
661
+ SELECT ${l1QueryCols} FROM l1_records
662
+ WHERE updated_time > ?
663
+ ORDER BY updated_time ASC
664
664
  `);
665
- this.stmtL1QueryMigrationCursor = this.db.prepare(`
666
- SELECT ${l1QueryCols} FROM l1_records
667
- WHERE record_id > ?
668
- ORDER BY record_id ASC
669
- LIMIT ?
665
+ this.stmtL1QueryMigrationCursor = this.db.prepare(`
666
+ SELECT ${l1QueryCols} FROM l1_records
667
+ WHERE record_id > ?
668
+ ORDER BY record_id ASC
669
+ LIMIT ?
670
670
  `);
671
671
  this.logger?.debug?.(`${TAG} Initialized (dimensions=${this.dimensions})`);
672
672
  return { needsReindex, reason: reindexReason };
@@ -1748,10 +1748,10 @@ export class VectorStore {
1748
1748
  this.db.exec("DELETE FROM l1_fts");
1749
1749
  // Read all L1 records from metadata table
1750
1750
  const l1Rows = this.db
1751
- .prepare(`
1752
- SELECT record_id, content, type, priority, scene_name,
1753
- session_key, session_id, timestamp_str, timestamp_start, timestamp_end, metadata_json
1754
- FROM l1_records
1751
+ .prepare(`
1752
+ SELECT record_id, content, type, priority, scene_name,
1753
+ session_key, session_id, timestamp_str, timestamp_start, timestamp_end, metadata_json
1754
+ FROM l1_records
1755
1755
  `)
1756
1756
  .all();
1757
1757
  let l1Count = 0;
@@ -1769,9 +1769,9 @@ export class VectorStore {
1769
1769
  // ── Rebuild L0 FTS ──
1770
1770
  this.db.exec("DELETE FROM l0_fts");
1771
1771
  const l0Rows = this.db
1772
- .prepare(`
1773
- SELECT record_id, message_text, session_key, session_id, role, recorded_at, timestamp
1774
- FROM l0_conversations
1772
+ .prepare(`
1773
+ SELECT record_id, message_text, session_key, session_id, role, recorded_at, timestamp
1774
+ FROM l0_conversations
1775
1775
  `)
1776
1776
  .all();
1777
1777
  let l0Count = 0;