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.
- package/client.js +4 -3
- package/index.js +436 -436
- package/package.json +1 -1
- package/vendor/tdai/adapters/standalone/llm-runner.js +274 -274
- package/vendor/tdai/config.js +366 -366
- package/vendor/tdai/core/hooks/auto-recall.js +13 -13
- package/vendor/tdai/core/prompts/l1-dedup.js +64 -64
- package/vendor/tdai/core/prompts/l1-extraction.js +98 -98
- package/vendor/tdai/core/prompts/persona-generation.js +125 -125
- package/vendor/tdai/core/prompts/scene-extraction.js +224 -224
- package/vendor/tdai/core/scene/scene-navigation.js +3 -3
- package/vendor/tdai/core/seed/seed-runtime.js +318 -318
- package/vendor/tdai/core/store/sqlite.js +190 -190
- package/vendor/tdai/core/tdai-core.js +450 -450
- package/vendor/tdai/utils/session-header-fetch.js +88 -88
|
@@ -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;
|