teleton 0.4.0 → 0.5.1
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/README.md +88 -13
- package/dist/BigInteger-DQ33LTTE.js +5 -0
- package/dist/chunk-4DU3C27M.js +30 -0
- package/dist/chunk-5WWR4CU3.js +124 -0
- package/dist/{chunk-7UPH62J2.js → chunk-BYTHCDZA.js} +261 -255
- package/dist/{chunk-E2NXSWOS.js → chunk-NUGDTPE4.js} +24 -64
- package/dist/{chunk-OA5L7GM6.js → chunk-O4R7V5Y2.js} +37 -5
- package/dist/chunk-QUAPFI2N.js +42 -0
- package/dist/{chunk-QU4ZOR35.js → chunk-RRB6BWU7.js} +3108 -3345
- package/dist/chunk-TSKJCWQQ.js +1263 -0
- package/dist/{chunk-B2PRMXOH.js → chunk-WL2Q3VRD.js} +0 -2
- package/dist/{chunk-OQGNS2FV.js → chunk-YBA6IBGT.js} +20 -5
- package/dist/cli/index.js +39 -172
- package/dist/{endpoint-FT2B2RZ2.js → endpoint-FLYNEZ2F.js} +1 -1
- package/dist/{get-my-gifts-AFKBG4YQ.js → get-my-gifts-KVULMBJ3.js} +1 -1
- package/dist/index.js +12 -12
- package/dist/{memory-SYTQ5P7P.js → memory-657W5AS6.js} +4 -5
- package/dist/{migrate-ITXMRRSZ.js → migrate-PMB2JVXH.js} +4 -5
- package/dist/server-BQY7CM2N.js +1120 -0
- package/dist/{task-dependency-resolver-GY6PEBIS.js → task-dependency-resolver-TRPILAHM.js} +2 -2
- package/dist/{task-executor-4QKTZZ3P.js → task-executor-N7XNVK5N.js} +1 -1
- package/dist/{tasks-M3QDPTGY.js → tasks-QSCWSMPS.js} +1 -1
- package/dist/{transcript-DF2Y6CFY.js → transcript-7V4UNID4.js} +1 -1
- package/dist/web/assets/index-CDMbujHf.css +1 -0
- package/dist/web/assets/index-DDX8oQ2z.js +67 -0
- package/dist/web/index.html +16 -0
- package/dist/web/logo_dark.png +0 -0
- package/package.json +23 -4
- package/dist/chunk-67QC5FBN.js +0 -60
- package/dist/chunk-A64NPEFL.js +0 -74
- package/dist/chunk-DUW5VBAZ.js +0 -133
- package/dist/chunk-QBGUCUOW.js +0 -16
- package/dist/scraper-SH7GS7TO.js +0 -282
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from "./chunk-A64NPEFL.js";
|
|
2
|
+
DEFAULT_FETCH_TIMEOUT_MS
|
|
3
|
+
} from "./chunk-4DU3C27M.js";
|
|
5
4
|
import {
|
|
6
5
|
EMBEDDING_CACHE_EVICTION_INTERVAL,
|
|
6
|
+
EMBEDDING_CACHE_EVICTION_RATIO,
|
|
7
7
|
EMBEDDING_CACHE_MAX_ENTRIES,
|
|
8
8
|
EMBEDDING_CACHE_TTL_DAYS,
|
|
9
|
-
|
|
9
|
+
HYBRID_SEARCH_MIN_SCORE,
|
|
10
10
|
KNOWLEDGE_CHUNK_SIZE,
|
|
11
11
|
SQLITE_CACHE_SIZE_KB,
|
|
12
12
|
SQLITE_MMAP_SIZE,
|
|
13
13
|
VOYAGE_BATCH_SIZE
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-O4R7V5Y2.js";
|
|
15
15
|
import {
|
|
16
16
|
TELETON_ROOT
|
|
17
17
|
} from "./chunk-EYWNOHMJ.js";
|
|
@@ -428,7 +428,7 @@ function setSchemaVersion(db, version) {
|
|
|
428
428
|
`
|
|
429
429
|
).run(version);
|
|
430
430
|
}
|
|
431
|
-
var CURRENT_SCHEMA_VERSION = "1.
|
|
431
|
+
var CURRENT_SCHEMA_VERSION = "1.10.1";
|
|
432
432
|
function runMigrations(db) {
|
|
433
433
|
const currentVersion = getSchemaVersion(db);
|
|
434
434
|
if (!currentVersion || versionLessThan(currentVersion, "1.1.0")) {
|
|
@@ -535,6 +535,47 @@ function runMigrations(db) {
|
|
|
535
535
|
throw error;
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
|
+
if (!currentVersion || versionLessThan(currentVersion, "1.10.0")) {
|
|
539
|
+
console.log("\u{1F504} Running migration 1.10.0: Add tool_config table for runtime tool management");
|
|
540
|
+
try {
|
|
541
|
+
db.exec(`
|
|
542
|
+
CREATE TABLE IF NOT EXISTS tool_config (
|
|
543
|
+
tool_name TEXT PRIMARY KEY,
|
|
544
|
+
enabled INTEGER NOT NULL DEFAULT 1 CHECK(enabled IN (0, 1)),
|
|
545
|
+
scope TEXT CHECK(scope IN ('always', 'dm-only', 'group-only', 'admin-only')),
|
|
546
|
+
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
547
|
+
updated_by INTEGER
|
|
548
|
+
);
|
|
549
|
+
`);
|
|
550
|
+
console.log("\u2705 Migration 1.10.0 complete: tool_config table created");
|
|
551
|
+
} catch (error) {
|
|
552
|
+
console.error("\u274C Migration 1.10.0 failed:", error);
|
|
553
|
+
throw error;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (!currentVersion || versionLessThan(currentVersion, "1.10.1")) {
|
|
557
|
+
console.log(
|
|
558
|
+
"\u{1F504} Running migration 1.10.1: Fix tool_config scope CHECK constraint (add admin-only)"
|
|
559
|
+
);
|
|
560
|
+
try {
|
|
561
|
+
db.exec(`
|
|
562
|
+
CREATE TABLE IF NOT EXISTS tool_config_new (
|
|
563
|
+
tool_name TEXT PRIMARY KEY,
|
|
564
|
+
enabled INTEGER NOT NULL DEFAULT 1 CHECK(enabled IN (0, 1)),
|
|
565
|
+
scope TEXT CHECK(scope IN ('always', 'dm-only', 'group-only', 'admin-only')),
|
|
566
|
+
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
567
|
+
updated_by INTEGER
|
|
568
|
+
);
|
|
569
|
+
INSERT OR IGNORE INTO tool_config_new SELECT * FROM tool_config;
|
|
570
|
+
DROP TABLE tool_config;
|
|
571
|
+
ALTER TABLE tool_config_new RENAME TO tool_config;
|
|
572
|
+
`);
|
|
573
|
+
console.log("\u2705 Migration 1.10.1 complete: tool_config CHECK constraint updated");
|
|
574
|
+
} catch (error) {
|
|
575
|
+
console.error("\u274C Migration 1.10.1 failed:", error);
|
|
576
|
+
throw error;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
538
579
|
setSchemaVersion(db, CURRENT_SCHEMA_VERSION);
|
|
539
580
|
}
|
|
540
581
|
|
|
@@ -603,33 +644,18 @@ var MemoryDatabase = class {
|
|
|
603
644
|
ensureSchema(this.db);
|
|
604
645
|
console.log("Migration complete");
|
|
605
646
|
}
|
|
606
|
-
/**
|
|
607
|
-
* Get the underlying better-sqlite3 database
|
|
608
|
-
*/
|
|
609
647
|
getDb() {
|
|
610
648
|
return this.db;
|
|
611
649
|
}
|
|
612
|
-
/**
|
|
613
|
-
* Check if vector search is available
|
|
614
|
-
*/
|
|
615
650
|
isVectorSearchReady() {
|
|
616
651
|
return this.vectorReady;
|
|
617
652
|
}
|
|
618
|
-
/**
|
|
619
|
-
* Get vector dimensions
|
|
620
|
-
*/
|
|
621
653
|
getVectorDimensions() {
|
|
622
654
|
return this.config.vectorDimensions;
|
|
623
655
|
}
|
|
624
|
-
/**
|
|
625
|
-
* Execute a function in a transaction
|
|
626
|
-
*/
|
|
627
656
|
transaction(fn) {
|
|
628
657
|
return this.db.transaction(fn)();
|
|
629
658
|
}
|
|
630
|
-
/**
|
|
631
|
-
* Execute an async function in a transaction
|
|
632
|
-
*/
|
|
633
659
|
async asyncTransaction(fn) {
|
|
634
660
|
const beginTrans = this.db.prepare("BEGIN");
|
|
635
661
|
const commitTrans = this.db.prepare("COMMIT");
|
|
@@ -644,9 +670,6 @@ var MemoryDatabase = class {
|
|
|
644
670
|
throw error;
|
|
645
671
|
}
|
|
646
672
|
}
|
|
647
|
-
/**
|
|
648
|
-
* Get database stats
|
|
649
|
-
*/
|
|
650
673
|
getStats() {
|
|
651
674
|
const knowledge = this.db.prepare(`SELECT COUNT(*) as c FROM knowledge`).get();
|
|
652
675
|
const sessions = this.db.prepare(`SELECT COUNT(*) as c FROM sessions`).get();
|
|
@@ -666,21 +689,15 @@ var MemoryDatabase = class {
|
|
|
666
689
|
vectorSearchEnabled: this.vectorReady
|
|
667
690
|
};
|
|
668
691
|
}
|
|
669
|
-
/**
|
|
670
|
-
* Vacuum the database to reclaim space
|
|
671
|
-
*/
|
|
672
692
|
vacuum() {
|
|
673
693
|
this.db.exec("VACUUM");
|
|
674
694
|
}
|
|
675
|
-
/**
|
|
676
|
-
* Optimize the database (ANALYZE)
|
|
677
|
-
*/
|
|
678
695
|
optimize() {
|
|
679
696
|
this.db.exec("ANALYZE");
|
|
680
697
|
}
|
|
681
698
|
/**
|
|
682
|
-
* Rebuild FTS indexes from existing data
|
|
683
|
-
* Call this if FTS triggers didn't fire correctly
|
|
699
|
+
* Rebuild FTS indexes from existing data.
|
|
700
|
+
* Call this if FTS triggers didn't fire correctly.
|
|
684
701
|
*/
|
|
685
702
|
rebuildFtsIndexes() {
|
|
686
703
|
this.db.exec(`DELETE FROM knowledge_fts`);
|
|
@@ -703,9 +720,6 @@ var MemoryDatabase = class {
|
|
|
703
720
|
}
|
|
704
721
|
return { knowledge: knowledgeRows.length, messages: messageRows.length };
|
|
705
722
|
}
|
|
706
|
-
/**
|
|
707
|
-
* Close the database connection
|
|
708
|
-
*/
|
|
709
723
|
close() {
|
|
710
724
|
if (this.db.open) {
|
|
711
725
|
this.db.close();
|
|
@@ -745,6 +759,63 @@ var NoopEmbeddingProvider = class {
|
|
|
745
759
|
}
|
|
746
760
|
};
|
|
747
761
|
|
|
762
|
+
// src/utils/fetch.ts
|
|
763
|
+
var DEFAULT_TIMEOUT_MS = DEFAULT_FETCH_TIMEOUT_MS;
|
|
764
|
+
function fetchWithTimeout(url, init) {
|
|
765
|
+
const { timeoutMs = DEFAULT_TIMEOUT_MS, ...fetchInit } = init ?? {};
|
|
766
|
+
if (fetchInit.signal) {
|
|
767
|
+
return fetch(url, fetchInit);
|
|
768
|
+
}
|
|
769
|
+
return fetch(url, {
|
|
770
|
+
...fetchInit,
|
|
771
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// src/constants/api-endpoints.ts
|
|
776
|
+
var TONAPI_BASE_URL = "https://tonapi.io/v2";
|
|
777
|
+
var _tonapiKey;
|
|
778
|
+
function setTonapiKey(key) {
|
|
779
|
+
_tonapiKey = key;
|
|
780
|
+
}
|
|
781
|
+
function tonapiHeaders() {
|
|
782
|
+
const headers = { Accept: "application/json" };
|
|
783
|
+
if (_tonapiKey) {
|
|
784
|
+
headers["Authorization"] = `Bearer ${_tonapiKey}`;
|
|
785
|
+
}
|
|
786
|
+
return headers;
|
|
787
|
+
}
|
|
788
|
+
var TONAPI_MAX_RPS = 5;
|
|
789
|
+
var _tonapiTimestamps = [];
|
|
790
|
+
async function waitForTonapiSlot() {
|
|
791
|
+
const clean = () => {
|
|
792
|
+
const cutoff = Date.now() - 1e3;
|
|
793
|
+
while (_tonapiTimestamps.length > 0 && _tonapiTimestamps[0] <= cutoff) {
|
|
794
|
+
_tonapiTimestamps.shift();
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
clean();
|
|
798
|
+
if (_tonapiTimestamps.length >= TONAPI_MAX_RPS) {
|
|
799
|
+
const waitMs = _tonapiTimestamps[0] + 1e3 - Date.now() + 50;
|
|
800
|
+
if (waitMs > 0) await new Promise((r) => setTimeout(r, waitMs));
|
|
801
|
+
clean();
|
|
802
|
+
}
|
|
803
|
+
_tonapiTimestamps.push(Date.now());
|
|
804
|
+
}
|
|
805
|
+
async function tonapiFetch(path, init) {
|
|
806
|
+
await waitForTonapiSlot();
|
|
807
|
+
return fetchWithTimeout(`${TONAPI_BASE_URL}${path}`, {
|
|
808
|
+
...init,
|
|
809
|
+
headers: { ...tonapiHeaders(), ...init?.headers }
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
var STONFI_API_BASE_URL = "https://api.ston.fi/v1";
|
|
813
|
+
var GECKOTERMINAL_API_URL = "https://api.geckoterminal.com/api/v2";
|
|
814
|
+
var COINGECKO_API_URL = "https://api.coingecko.com/api/v3";
|
|
815
|
+
var OPENAI_TTS_URL = "https://api.openai.com/v1/audio/speech";
|
|
816
|
+
var ELEVENLABS_TTS_URL = "https://api.elevenlabs.io/v1/text-to-speech";
|
|
817
|
+
var VOYAGE_API_URL = "https://api.voyageai.com/v1";
|
|
818
|
+
|
|
748
819
|
// src/memory/embeddings/anthropic.ts
|
|
749
820
|
var AnthropicEmbeddingProvider = class {
|
|
750
821
|
id = "anthropic";
|
|
@@ -813,6 +884,10 @@ function getExtractor(model) {
|
|
|
813
884
|
}).then((ext) => {
|
|
814
885
|
console.log(`\u2705 Local embedding model ready`);
|
|
815
886
|
return ext;
|
|
887
|
+
}).catch((err) => {
|
|
888
|
+
console.error(`\u274C Failed to load embedding model: ${err.message}`);
|
|
889
|
+
extractorPromise = null;
|
|
890
|
+
throw err;
|
|
816
891
|
});
|
|
817
892
|
}
|
|
818
893
|
return extractorPromise;
|
|
@@ -945,7 +1020,7 @@ var CachedEmbeddingProvider = class {
|
|
|
945
1020
|
this.db.prepare(`DELETE FROM embedding_cache WHERE accessed_at < ?`).run(cutoff);
|
|
946
1021
|
const count = this.db.prepare(`SELECT COUNT(*) as cnt FROM embedding_cache`).get().cnt;
|
|
947
1022
|
if (count > EMBEDDING_CACHE_MAX_ENTRIES) {
|
|
948
|
-
const toDelete = Math.ceil(count *
|
|
1023
|
+
const toDelete = Math.ceil(count * EMBEDDING_CACHE_EVICTION_RATIO);
|
|
949
1024
|
this.db.prepare(
|
|
950
1025
|
`DELETE FROM embedding_cache WHERE (hash, model, provider) IN (
|
|
951
1026
|
SELECT hash, model, provider FROM embedding_cache ORDER BY accessed_at ASC LIMIT ?
|
|
@@ -1008,9 +1083,6 @@ var KnowledgeIndexer = class {
|
|
|
1008
1083
|
this.embedder = embedder;
|
|
1009
1084
|
this.vectorEnabled = vectorEnabled;
|
|
1010
1085
|
}
|
|
1011
|
-
/**
|
|
1012
|
-
* Index all memory files
|
|
1013
|
-
*/
|
|
1014
1086
|
async indexAll() {
|
|
1015
1087
|
const files = this.listMemoryFiles();
|
|
1016
1088
|
let indexed = 0;
|
|
@@ -1025,9 +1097,6 @@ var KnowledgeIndexer = class {
|
|
|
1025
1097
|
}
|
|
1026
1098
|
return { indexed, skipped };
|
|
1027
1099
|
}
|
|
1028
|
-
/**
|
|
1029
|
-
* Index a single file
|
|
1030
|
-
*/
|
|
1031
1100
|
async indexFile(absPath) {
|
|
1032
1101
|
if (!existsSync3(absPath) || !absPath.endsWith(".md")) {
|
|
1033
1102
|
return false;
|
|
@@ -1039,43 +1108,42 @@ var KnowledgeIndexer = class {
|
|
|
1039
1108
|
if (existing?.hash === fileHash) {
|
|
1040
1109
|
return false;
|
|
1041
1110
|
}
|
|
1042
|
-
if (this.vectorEnabled) {
|
|
1043
|
-
this.db.prepare(
|
|
1044
|
-
`DELETE FROM knowledge_vec WHERE id IN (
|
|
1045
|
-
SELECT id FROM knowledge WHERE path = ? AND source = 'memory'
|
|
1046
|
-
)`
|
|
1047
|
-
).run(relPath);
|
|
1048
|
-
}
|
|
1049
|
-
this.db.prepare(`DELETE FROM knowledge WHERE path = ? AND source = 'memory'`).run(relPath);
|
|
1050
1111
|
const chunks = this.chunkMarkdown(content, relPath);
|
|
1051
1112
|
const texts = chunks.map((c) => c.text);
|
|
1052
1113
|
const embeddings = await this.embedder.embedBatch(texts);
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
const embedding = embeddings[i] ?? [];
|
|
1061
|
-
insert.run(
|
|
1062
|
-
chunk.id,
|
|
1063
|
-
chunk.path,
|
|
1064
|
-
chunk.text,
|
|
1065
|
-
serializeEmbedding(embedding),
|
|
1066
|
-
chunk.startLine,
|
|
1067
|
-
chunk.endLine,
|
|
1068
|
-
chunk.hash
|
|
1069
|
-
);
|
|
1070
|
-
if (insertVec && embedding.length > 0) {
|
|
1071
|
-
insertVec.run(chunk.id, serializeEmbedding(embedding));
|
|
1114
|
+
this.db.transaction(() => {
|
|
1115
|
+
if (this.vectorEnabled) {
|
|
1116
|
+
this.db.prepare(
|
|
1117
|
+
`DELETE FROM knowledge_vec WHERE id IN (
|
|
1118
|
+
SELECT id FROM knowledge WHERE path = ? AND source = 'memory'
|
|
1119
|
+
)`
|
|
1120
|
+
).run(relPath);
|
|
1072
1121
|
}
|
|
1073
|
-
|
|
1122
|
+
this.db.prepare(`DELETE FROM knowledge WHERE path = ? AND source = 'memory'`).run(relPath);
|
|
1123
|
+
const insert = this.db.prepare(`
|
|
1124
|
+
INSERT INTO knowledge (id, source, path, text, embedding, start_line, end_line, hash)
|
|
1125
|
+
VALUES (?, 'memory', ?, ?, ?, ?, ?, ?)
|
|
1126
|
+
`);
|
|
1127
|
+
const insertVec = this.vectorEnabled ? this.db.prepare(`INSERT INTO knowledge_vec (id, embedding) VALUES (?, ?)`) : null;
|
|
1128
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
1129
|
+
const chunk = chunks[i];
|
|
1130
|
+
const embedding = embeddings[i] ?? [];
|
|
1131
|
+
insert.run(
|
|
1132
|
+
chunk.id,
|
|
1133
|
+
chunk.path,
|
|
1134
|
+
chunk.text,
|
|
1135
|
+
serializeEmbedding(embedding),
|
|
1136
|
+
chunk.startLine,
|
|
1137
|
+
chunk.endLine,
|
|
1138
|
+
chunk.hash
|
|
1139
|
+
);
|
|
1140
|
+
if (insertVec && embedding.length > 0) {
|
|
1141
|
+
insertVec.run(chunk.id, serializeEmbedding(embedding));
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
})();
|
|
1074
1145
|
return true;
|
|
1075
1146
|
}
|
|
1076
|
-
/**
|
|
1077
|
-
* List all memory files
|
|
1078
|
-
*/
|
|
1079
1147
|
listMemoryFiles() {
|
|
1080
1148
|
const files = [];
|
|
1081
1149
|
const memoryMd = join2(this.workspaceDir, "MEMORY.md");
|
|
@@ -1095,49 +1163,58 @@ var KnowledgeIndexer = class {
|
|
|
1095
1163
|
return files;
|
|
1096
1164
|
}
|
|
1097
1165
|
/**
|
|
1098
|
-
* Chunk markdown content
|
|
1166
|
+
* Chunk markdown content with structure awareness.
|
|
1167
|
+
* Respects heading boundaries, code blocks, and list groups.
|
|
1168
|
+
* Target: KNOWLEDGE_CHUNK_SIZE chars, hard max: 2x target.
|
|
1099
1169
|
*/
|
|
1100
1170
|
chunkMarkdown(content, path) {
|
|
1101
1171
|
const lines = content.split("\n");
|
|
1102
1172
|
const chunks = [];
|
|
1103
|
-
const
|
|
1104
|
-
const
|
|
1173
|
+
const targetSize = KNOWLEDGE_CHUNK_SIZE;
|
|
1174
|
+
const hardMax = targetSize * 2;
|
|
1105
1175
|
let currentChunk = "";
|
|
1106
1176
|
let startLine = 1;
|
|
1107
1177
|
let currentLine = 1;
|
|
1178
|
+
let inCodeBlock = false;
|
|
1179
|
+
const flushChunk = () => {
|
|
1180
|
+
const text = currentChunk.trim();
|
|
1181
|
+
if (text.length > 0) {
|
|
1182
|
+
chunks.push({
|
|
1183
|
+
id: hashText(`${path}:${startLine}:${currentLine - 1}`),
|
|
1184
|
+
source: "memory",
|
|
1185
|
+
path,
|
|
1186
|
+
text,
|
|
1187
|
+
startLine,
|
|
1188
|
+
endLine: currentLine - 1,
|
|
1189
|
+
hash: hashText(text)
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
currentChunk = "";
|
|
1193
|
+
startLine = currentLine;
|
|
1194
|
+
};
|
|
1108
1195
|
for (const line of lines) {
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1196
|
+
if (line.trimStart().startsWith("```")) {
|
|
1197
|
+
inCodeBlock = !inCodeBlock;
|
|
1198
|
+
}
|
|
1199
|
+
if (!inCodeBlock && currentChunk.length >= targetSize) {
|
|
1200
|
+
const isHeading = /^#{1,6}\s/.test(line);
|
|
1201
|
+
const isBlankLine = line.trim() === "";
|
|
1202
|
+
const isHorizontalRule = /^(-{3,}|\*{3,}|_{3,})\s*$/.test(line.trim());
|
|
1203
|
+
if (isHeading) {
|
|
1204
|
+
flushChunk();
|
|
1205
|
+
} else if ((isBlankLine || isHorizontalRule) && currentChunk.length >= targetSize) {
|
|
1206
|
+
currentChunk += line + "\n";
|
|
1207
|
+
currentLine++;
|
|
1208
|
+
flushChunk();
|
|
1209
|
+
continue;
|
|
1210
|
+
} else if (currentChunk.length >= hardMax) {
|
|
1211
|
+
flushChunk();
|
|
1122
1212
|
}
|
|
1123
|
-
const overlapText = currentChunk.slice(-overlap);
|
|
1124
|
-
currentChunk = overlapText;
|
|
1125
|
-
startLine = currentLine + 1;
|
|
1126
1213
|
}
|
|
1214
|
+
currentChunk += line + "\n";
|
|
1127
1215
|
currentLine++;
|
|
1128
1216
|
}
|
|
1129
|
-
|
|
1130
|
-
if (text.length > 0) {
|
|
1131
|
-
chunks.push({
|
|
1132
|
-
id: hashText(`${path}:${startLine}:${currentLine}`),
|
|
1133
|
-
source: "memory",
|
|
1134
|
-
path,
|
|
1135
|
-
text,
|
|
1136
|
-
startLine,
|
|
1137
|
-
endLine: currentLine,
|
|
1138
|
-
hash: hashText(text)
|
|
1139
|
-
});
|
|
1140
|
-
}
|
|
1217
|
+
flushChunk();
|
|
1141
1218
|
return chunks;
|
|
1142
1219
|
}
|
|
1143
1220
|
};
|
|
@@ -1150,9 +1227,6 @@ var SessionStore = class {
|
|
|
1150
1227
|
this.embedder = embedder;
|
|
1151
1228
|
this.vectorEnabled = vectorEnabled;
|
|
1152
1229
|
}
|
|
1153
|
-
/**
|
|
1154
|
-
* Create a new session
|
|
1155
|
-
*/
|
|
1156
1230
|
createSession(chatId) {
|
|
1157
1231
|
const id = randomUUID();
|
|
1158
1232
|
const now = Math.floor(Date.now() / 1e3);
|
|
@@ -1170,9 +1244,6 @@ var SessionStore = class {
|
|
|
1170
1244
|
tokensUsed: 0
|
|
1171
1245
|
};
|
|
1172
1246
|
}
|
|
1173
|
-
/**
|
|
1174
|
-
* End a session with summary
|
|
1175
|
-
*/
|
|
1176
1247
|
endSession(sessionId, summary, tokensUsed = 0) {
|
|
1177
1248
|
const now = Math.floor(Date.now() / 1e3);
|
|
1178
1249
|
this.db.prepare(
|
|
@@ -1183,9 +1254,6 @@ var SessionStore = class {
|
|
|
1183
1254
|
`
|
|
1184
1255
|
).run(now, summary, tokensUsed, sessionId);
|
|
1185
1256
|
}
|
|
1186
|
-
/**
|
|
1187
|
-
* Update message count for a session
|
|
1188
|
-
*/
|
|
1189
1257
|
incrementMessageCount(sessionId, count = 1) {
|
|
1190
1258
|
this.db.prepare(
|
|
1191
1259
|
`
|
|
@@ -1195,9 +1263,6 @@ var SessionStore = class {
|
|
|
1195
1263
|
`
|
|
1196
1264
|
).run(count, sessionId);
|
|
1197
1265
|
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Get a session by ID
|
|
1200
|
-
*/
|
|
1201
1266
|
getSession(id) {
|
|
1202
1267
|
const row = this.db.prepare(`SELECT * FROM sessions WHERE id = ?`).get(id);
|
|
1203
1268
|
if (!row) return void 0;
|
|
@@ -1206,14 +1271,11 @@ var SessionStore = class {
|
|
|
1206
1271
|
chatId: row.chat_id,
|
|
1207
1272
|
startedAt: new Date(row.started_at * 1e3),
|
|
1208
1273
|
endedAt: row.ended_at ? new Date(row.ended_at * 1e3) : void 0,
|
|
1209
|
-
summary: row.summary,
|
|
1274
|
+
summary: row.summary ?? void 0,
|
|
1210
1275
|
messageCount: row.message_count,
|
|
1211
1276
|
tokensUsed: row.tokens_used
|
|
1212
1277
|
};
|
|
1213
1278
|
}
|
|
1214
|
-
/**
|
|
1215
|
-
* Get active (not ended) sessions
|
|
1216
|
-
*/
|
|
1217
1279
|
getActiveSessions() {
|
|
1218
1280
|
const rows = this.db.prepare(
|
|
1219
1281
|
`
|
|
@@ -1227,14 +1289,11 @@ var SessionStore = class {
|
|
|
1227
1289
|
chatId: row.chat_id,
|
|
1228
1290
|
startedAt: new Date(row.started_at * 1e3),
|
|
1229
1291
|
endedAt: void 0,
|
|
1230
|
-
summary: row.summary,
|
|
1292
|
+
summary: row.summary ?? void 0,
|
|
1231
1293
|
messageCount: row.message_count,
|
|
1232
1294
|
tokensUsed: row.tokens_used
|
|
1233
1295
|
}));
|
|
1234
1296
|
}
|
|
1235
|
-
/**
|
|
1236
|
-
* Get sessions for a specific chat
|
|
1237
|
-
*/
|
|
1238
1297
|
getSessionsByChat(chatId, limit = 50) {
|
|
1239
1298
|
const rows = this.db.prepare(
|
|
1240
1299
|
`
|
|
@@ -1249,14 +1308,14 @@ var SessionStore = class {
|
|
|
1249
1308
|
chatId: row.chat_id,
|
|
1250
1309
|
startedAt: new Date(row.started_at * 1e3),
|
|
1251
1310
|
endedAt: row.ended_at ? new Date(row.ended_at * 1e3) : void 0,
|
|
1252
|
-
summary: row.summary,
|
|
1311
|
+
summary: row.summary ?? void 0,
|
|
1253
1312
|
messageCount: row.message_count,
|
|
1254
1313
|
tokensUsed: row.tokens_used
|
|
1255
1314
|
}));
|
|
1256
1315
|
}
|
|
1257
1316
|
/**
|
|
1258
|
-
* Index a session for search
|
|
1259
|
-
*
|
|
1317
|
+
* Index a session for search after ending.
|
|
1318
|
+
* Creates a knowledge entry from the session summary for future retrieval.
|
|
1260
1319
|
*/
|
|
1261
1320
|
async indexSession(sessionId) {
|
|
1262
1321
|
const session = this.getSession(sessionId);
|
|
@@ -1291,9 +1350,6 @@ ${session.summary}`;
|
|
|
1291
1350
|
console.error("Error indexing session:", error);
|
|
1292
1351
|
}
|
|
1293
1352
|
}
|
|
1294
|
-
/**
|
|
1295
|
-
* Delete a session
|
|
1296
|
-
*/
|
|
1297
1353
|
deleteSession(sessionId) {
|
|
1298
1354
|
const knowledgeId = `session:${sessionId}`;
|
|
1299
1355
|
if (this.vectorEnabled) {
|
|
@@ -1311,18 +1367,12 @@ var MessageStore = class {
|
|
|
1311
1367
|
this.embedder = embedder;
|
|
1312
1368
|
this.vectorEnabled = vectorEnabled;
|
|
1313
1369
|
}
|
|
1314
|
-
/**
|
|
1315
|
-
* Ensure chat exists in database
|
|
1316
|
-
*/
|
|
1317
1370
|
ensureChat(chatId, isGroup = false) {
|
|
1318
1371
|
const existing = this.db.prepare(`SELECT id FROM tg_chats WHERE id = ?`).get(chatId);
|
|
1319
1372
|
if (!existing) {
|
|
1320
1373
|
this.db.prepare(`INSERT INTO tg_chats (id, type, is_monitored) VALUES (?, ?, 1)`).run(chatId, isGroup ? "group" : "dm");
|
|
1321
1374
|
}
|
|
1322
1375
|
}
|
|
1323
|
-
/**
|
|
1324
|
-
* Ensure user exists in database
|
|
1325
|
-
*/
|
|
1326
1376
|
ensureUser(userId) {
|
|
1327
1377
|
if (!userId) return;
|
|
1328
1378
|
const existing = this.db.prepare(`SELECT id FROM tg_users WHERE id = ?`).get(userId);
|
|
@@ -1330,9 +1380,6 @@ var MessageStore = class {
|
|
|
1330
1380
|
this.db.prepare(`INSERT INTO tg_users (id) VALUES (?)`).run(userId);
|
|
1331
1381
|
}
|
|
1332
1382
|
}
|
|
1333
|
-
/**
|
|
1334
|
-
* Store a message
|
|
1335
|
-
*/
|
|
1336
1383
|
async storeMessage(message) {
|
|
1337
1384
|
this.ensureChat(message.chatId);
|
|
1338
1385
|
if (message.senderId) {
|
|
@@ -1340,34 +1387,33 @@ var MessageStore = class {
|
|
|
1340
1387
|
}
|
|
1341
1388
|
const embedding = this.vectorEnabled && message.text ? await this.embedder.embedQuery(message.text) : [];
|
|
1342
1389
|
const embeddingBuffer = serializeEmbedding(embedding);
|
|
1343
|
-
this.db.
|
|
1390
|
+
this.db.transaction(() => {
|
|
1391
|
+
this.db.prepare(
|
|
1392
|
+
`
|
|
1393
|
+
INSERT OR REPLACE INTO tg_messages (
|
|
1394
|
+
id, chat_id, sender_id, text, embedding, reply_to_id,
|
|
1395
|
+
is_from_agent, has_media, media_type, timestamp
|
|
1396
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1344
1397
|
`
|
|
1345
|
-
|
|
1346
|
-
id,
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
this.db.prepare(`DELETE FROM tg_messages_vec WHERE id = ?`).run(message.id);
|
|
1364
|
-
this.db.prepare(`INSERT INTO tg_messages_vec (id, embedding) VALUES (?, ?)`).run(message.id, embeddingBuffer);
|
|
1365
|
-
}
|
|
1366
|
-
this.db.prepare(`UPDATE tg_chats SET last_message_at = ?, last_message_id = ? WHERE id = ?`).run(message.timestamp, message.id, message.chatId);
|
|
1398
|
+
).run(
|
|
1399
|
+
message.id,
|
|
1400
|
+
message.chatId,
|
|
1401
|
+
message.senderId,
|
|
1402
|
+
message.text,
|
|
1403
|
+
embeddingBuffer,
|
|
1404
|
+
message.replyToId,
|
|
1405
|
+
message.isFromAgent ? 1 : 0,
|
|
1406
|
+
message.hasMedia ? 1 : 0,
|
|
1407
|
+
message.mediaType,
|
|
1408
|
+
message.timestamp
|
|
1409
|
+
);
|
|
1410
|
+
if (this.vectorEnabled && embedding.length > 0 && message.text) {
|
|
1411
|
+
this.db.prepare(`DELETE FROM tg_messages_vec WHERE id = ?`).run(message.id);
|
|
1412
|
+
this.db.prepare(`INSERT INTO tg_messages_vec (id, embedding) VALUES (?, ?)`).run(message.id, embeddingBuffer);
|
|
1413
|
+
}
|
|
1414
|
+
this.db.prepare(`UPDATE tg_chats SET last_message_at = ?, last_message_id = ? WHERE id = ?`).run(message.timestamp, message.id, message.chatId);
|
|
1415
|
+
})();
|
|
1367
1416
|
}
|
|
1368
|
-
/**
|
|
1369
|
-
* Get recent messages from a chat
|
|
1370
|
-
*/
|
|
1371
1417
|
getRecentMessages(chatId, limit = 20) {
|
|
1372
1418
|
const rows = this.db.prepare(
|
|
1373
1419
|
`
|
|
@@ -1397,9 +1443,6 @@ var ChatStore = class {
|
|
|
1397
1443
|
constructor(db) {
|
|
1398
1444
|
this.db = db;
|
|
1399
1445
|
}
|
|
1400
|
-
/**
|
|
1401
|
-
* Create or update a chat
|
|
1402
|
-
*/
|
|
1403
1446
|
upsertChat(chat) {
|
|
1404
1447
|
const now = Math.floor(Date.now() / 1e3);
|
|
1405
1448
|
this.db.prepare(
|
|
@@ -1431,9 +1474,6 @@ var ChatStore = class {
|
|
|
1431
1474
|
now
|
|
1432
1475
|
);
|
|
1433
1476
|
}
|
|
1434
|
-
/**
|
|
1435
|
-
* Get a chat by ID
|
|
1436
|
-
*/
|
|
1437
1477
|
getChat(id) {
|
|
1438
1478
|
const row = this.db.prepare(
|
|
1439
1479
|
`
|
|
@@ -1444,20 +1484,17 @@ var ChatStore = class {
|
|
|
1444
1484
|
return {
|
|
1445
1485
|
id: row.id,
|
|
1446
1486
|
type: row.type,
|
|
1447
|
-
title: row.title,
|
|
1448
|
-
username: row.username,
|
|
1449
|
-
memberCount: row.member_count,
|
|
1487
|
+
title: row.title ?? void 0,
|
|
1488
|
+
username: row.username ?? void 0,
|
|
1489
|
+
memberCount: row.member_count ?? void 0,
|
|
1450
1490
|
isMonitored: Boolean(row.is_monitored),
|
|
1451
1491
|
isArchived: Boolean(row.is_archived),
|
|
1452
|
-
lastMessageId: row.last_message_id,
|
|
1492
|
+
lastMessageId: row.last_message_id ?? void 0,
|
|
1453
1493
|
lastMessageAt: row.last_message_at ? new Date(row.last_message_at * 1e3) : void 0,
|
|
1454
1494
|
createdAt: new Date(row.created_at * 1e3),
|
|
1455
1495
|
updatedAt: new Date(row.updated_at * 1e3)
|
|
1456
1496
|
};
|
|
1457
1497
|
}
|
|
1458
|
-
/**
|
|
1459
|
-
* Get active (monitored, non-archived) chats
|
|
1460
|
-
*/
|
|
1461
1498
|
getActiveChats(limit = 50) {
|
|
1462
1499
|
const rows = this.db.prepare(
|
|
1463
1500
|
`
|
|
@@ -1470,20 +1507,17 @@ var ChatStore = class {
|
|
|
1470
1507
|
return rows.map((row) => ({
|
|
1471
1508
|
id: row.id,
|
|
1472
1509
|
type: row.type,
|
|
1473
|
-
title: row.title,
|
|
1474
|
-
username: row.username,
|
|
1475
|
-
memberCount: row.member_count,
|
|
1510
|
+
title: row.title ?? void 0,
|
|
1511
|
+
username: row.username ?? void 0,
|
|
1512
|
+
memberCount: row.member_count ?? void 0,
|
|
1476
1513
|
isMonitored: Boolean(row.is_monitored),
|
|
1477
1514
|
isArchived: Boolean(row.is_archived),
|
|
1478
|
-
lastMessageId: row.last_message_id,
|
|
1515
|
+
lastMessageId: row.last_message_id ?? void 0,
|
|
1479
1516
|
lastMessageAt: row.last_message_at ? new Date(row.last_message_at * 1e3) : void 0,
|
|
1480
1517
|
createdAt: new Date(row.created_at * 1e3),
|
|
1481
1518
|
updatedAt: new Date(row.updated_at * 1e3)
|
|
1482
1519
|
}));
|
|
1483
1520
|
}
|
|
1484
|
-
/**
|
|
1485
|
-
* Update last message info
|
|
1486
|
-
*/
|
|
1487
1521
|
updateLastMessage(chatId, messageId, timestamp) {
|
|
1488
1522
|
this.db.prepare(
|
|
1489
1523
|
`
|
|
@@ -1493,9 +1527,6 @@ var ChatStore = class {
|
|
|
1493
1527
|
`
|
|
1494
1528
|
).run(messageId, Math.floor(timestamp.getTime() / 1e3), chatId);
|
|
1495
1529
|
}
|
|
1496
|
-
/**
|
|
1497
|
-
* Archive a chat
|
|
1498
|
-
*/
|
|
1499
1530
|
archiveChat(chatId) {
|
|
1500
1531
|
this.db.prepare(
|
|
1501
1532
|
`
|
|
@@ -1505,9 +1536,6 @@ var ChatStore = class {
|
|
|
1505
1536
|
`
|
|
1506
1537
|
).run(chatId);
|
|
1507
1538
|
}
|
|
1508
|
-
/**
|
|
1509
|
-
* Unarchive a chat
|
|
1510
|
-
*/
|
|
1511
1539
|
unarchiveChat(chatId) {
|
|
1512
1540
|
this.db.prepare(
|
|
1513
1541
|
`
|
|
@@ -1517,9 +1545,6 @@ var ChatStore = class {
|
|
|
1517
1545
|
`
|
|
1518
1546
|
).run(chatId);
|
|
1519
1547
|
}
|
|
1520
|
-
/**
|
|
1521
|
-
* Set monitoring status
|
|
1522
|
-
*/
|
|
1523
1548
|
setMonitored(chatId, monitored) {
|
|
1524
1549
|
this.db.prepare(
|
|
1525
1550
|
`
|
|
@@ -1536,9 +1561,6 @@ var UserStore = class {
|
|
|
1536
1561
|
constructor(db) {
|
|
1537
1562
|
this.db = db;
|
|
1538
1563
|
}
|
|
1539
|
-
/**
|
|
1540
|
-
* Create or update a user
|
|
1541
|
-
*/
|
|
1542
1564
|
upsertUser(user) {
|
|
1543
1565
|
const now = Math.floor(Date.now() / 1e3);
|
|
1544
1566
|
const existing = this.db.prepare(`SELECT id FROM tg_users WHERE id = ?`).get(user.id);
|
|
@@ -1577,17 +1599,14 @@ var UserStore = class {
|
|
|
1577
1599
|
);
|
|
1578
1600
|
}
|
|
1579
1601
|
}
|
|
1580
|
-
/**
|
|
1581
|
-
* Get a user by ID
|
|
1582
|
-
*/
|
|
1583
1602
|
getUser(id) {
|
|
1584
1603
|
const row = this.db.prepare(`SELECT * FROM tg_users WHERE id = ?`).get(id);
|
|
1585
1604
|
if (!row) return void 0;
|
|
1586
1605
|
return {
|
|
1587
1606
|
id: row.id,
|
|
1588
|
-
username: row.username,
|
|
1589
|
-
firstName: row.first_name,
|
|
1590
|
-
lastName: row.last_name,
|
|
1607
|
+
username: row.username ?? void 0,
|
|
1608
|
+
firstName: row.first_name ?? void 0,
|
|
1609
|
+
lastName: row.last_name ?? void 0,
|
|
1591
1610
|
isBot: Boolean(row.is_bot),
|
|
1592
1611
|
isAdmin: Boolean(row.is_admin),
|
|
1593
1612
|
isAllowed: Boolean(row.is_allowed),
|
|
@@ -1596,17 +1615,14 @@ var UserStore = class {
|
|
|
1596
1615
|
messageCount: row.message_count
|
|
1597
1616
|
};
|
|
1598
1617
|
}
|
|
1599
|
-
/**
|
|
1600
|
-
* Get a user by username
|
|
1601
|
-
*/
|
|
1602
1618
|
getUserByUsername(username) {
|
|
1603
1619
|
const row = this.db.prepare(`SELECT * FROM tg_users WHERE username = ?`).get(username.replace("@", ""));
|
|
1604
1620
|
if (!row) return void 0;
|
|
1605
1621
|
return {
|
|
1606
1622
|
id: row.id,
|
|
1607
|
-
username: row.username,
|
|
1608
|
-
firstName: row.first_name,
|
|
1609
|
-
lastName: row.last_name,
|
|
1623
|
+
username: row.username ?? void 0,
|
|
1624
|
+
firstName: row.first_name ?? void 0,
|
|
1625
|
+
lastName: row.last_name ?? void 0,
|
|
1610
1626
|
isBot: Boolean(row.is_bot),
|
|
1611
1627
|
isAdmin: Boolean(row.is_admin),
|
|
1612
1628
|
isAllowed: Boolean(row.is_allowed),
|
|
@@ -1615,9 +1631,6 @@ var UserStore = class {
|
|
|
1615
1631
|
messageCount: row.message_count
|
|
1616
1632
|
};
|
|
1617
1633
|
}
|
|
1618
|
-
/**
|
|
1619
|
-
* Update last seen timestamp
|
|
1620
|
-
*/
|
|
1621
1634
|
updateLastSeen(userId) {
|
|
1622
1635
|
this.db.prepare(
|
|
1623
1636
|
`
|
|
@@ -1627,9 +1640,6 @@ var UserStore = class {
|
|
|
1627
1640
|
`
|
|
1628
1641
|
).run(userId);
|
|
1629
1642
|
}
|
|
1630
|
-
/**
|
|
1631
|
-
* Increment message count
|
|
1632
|
-
*/
|
|
1633
1643
|
incrementMessageCount(userId) {
|
|
1634
1644
|
this.db.prepare(
|
|
1635
1645
|
`
|
|
@@ -1639,9 +1649,6 @@ var UserStore = class {
|
|
|
1639
1649
|
`
|
|
1640
1650
|
).run(userId);
|
|
1641
1651
|
}
|
|
1642
|
-
/**
|
|
1643
|
-
* Set admin status
|
|
1644
|
-
*/
|
|
1645
1652
|
setAdmin(userId, isAdmin) {
|
|
1646
1653
|
this.db.prepare(
|
|
1647
1654
|
`
|
|
@@ -1651,9 +1658,6 @@ var UserStore = class {
|
|
|
1651
1658
|
`
|
|
1652
1659
|
).run(isAdmin ? 1 : 0, userId);
|
|
1653
1660
|
}
|
|
1654
|
-
/**
|
|
1655
|
-
* Set allowed status
|
|
1656
|
-
*/
|
|
1657
1661
|
setAllowed(userId, isAllowed) {
|
|
1658
1662
|
this.db.prepare(
|
|
1659
1663
|
`
|
|
@@ -1663,9 +1667,6 @@ var UserStore = class {
|
|
|
1663
1667
|
`
|
|
1664
1668
|
).run(isAllowed ? 1 : 0, userId);
|
|
1665
1669
|
}
|
|
1666
|
-
/**
|
|
1667
|
-
* Get all admins
|
|
1668
|
-
*/
|
|
1669
1670
|
getAdmins() {
|
|
1670
1671
|
const rows = this.db.prepare(
|
|
1671
1672
|
`
|
|
@@ -1676,9 +1677,9 @@ var UserStore = class {
|
|
|
1676
1677
|
).all();
|
|
1677
1678
|
return rows.map((row) => ({
|
|
1678
1679
|
id: row.id,
|
|
1679
|
-
username: row.username,
|
|
1680
|
-
firstName: row.first_name,
|
|
1681
|
-
lastName: row.last_name,
|
|
1680
|
+
username: row.username ?? void 0,
|
|
1681
|
+
firstName: row.first_name ?? void 0,
|
|
1682
|
+
lastName: row.last_name ?? void 0,
|
|
1682
1683
|
isBot: Boolean(row.is_bot),
|
|
1683
1684
|
isAdmin: Boolean(row.is_admin),
|
|
1684
1685
|
isAllowed: Boolean(row.is_allowed),
|
|
@@ -1687,9 +1688,6 @@ var UserStore = class {
|
|
|
1687
1688
|
messageCount: row.message_count
|
|
1688
1689
|
}));
|
|
1689
1690
|
}
|
|
1690
|
-
/**
|
|
1691
|
-
* Get recently active users
|
|
1692
|
-
*/
|
|
1693
1691
|
getRecentUsers(limit = 50) {
|
|
1694
1692
|
const rows = this.db.prepare(
|
|
1695
1693
|
`
|
|
@@ -1700,9 +1698,9 @@ var UserStore = class {
|
|
|
1700
1698
|
).all(limit);
|
|
1701
1699
|
return rows.map((row) => ({
|
|
1702
1700
|
id: row.id,
|
|
1703
|
-
username: row.username,
|
|
1704
|
-
firstName: row.first_name,
|
|
1705
|
-
lastName: row.last_name,
|
|
1701
|
+
username: row.username ?? void 0,
|
|
1702
|
+
firstName: row.first_name ?? void 0,
|
|
1703
|
+
lastName: row.last_name ?? void 0,
|
|
1706
1704
|
isBot: Boolean(row.is_bot),
|
|
1707
1705
|
isAdmin: Boolean(row.is_admin),
|
|
1708
1706
|
isAllowed: Boolean(row.is_allowed),
|
|
@@ -1722,30 +1720,20 @@ var HybridSearch = class {
|
|
|
1722
1720
|
this.db = db;
|
|
1723
1721
|
this.vectorEnabled = vectorEnabled;
|
|
1724
1722
|
}
|
|
1725
|
-
/**
|
|
1726
|
-
* Search in knowledge base
|
|
1727
|
-
*/
|
|
1728
1723
|
async searchKnowledge(query, queryEmbedding, options = {}) {
|
|
1729
1724
|
const limit = options.limit ?? 10;
|
|
1730
|
-
const vectorWeight = options.vectorWeight ?? 0.
|
|
1731
|
-
const keywordWeight = options.keywordWeight ?? 0.
|
|
1732
|
-
const vectorResults = this.vectorEnabled ? this.vectorSearchKnowledge(queryEmbedding, Math.ceil(limit *
|
|
1733
|
-
const keywordResults = this.keywordSearchKnowledge(query, Math.ceil(limit *
|
|
1725
|
+
const vectorWeight = options.vectorWeight ?? 0.5;
|
|
1726
|
+
const keywordWeight = options.keywordWeight ?? 0.5;
|
|
1727
|
+
const vectorResults = this.vectorEnabled ? this.vectorSearchKnowledge(queryEmbedding, Math.ceil(limit * 3)) : [];
|
|
1728
|
+
const keywordResults = this.keywordSearchKnowledge(query, Math.ceil(limit * 3));
|
|
1734
1729
|
return this.mergeResults(vectorResults, keywordResults, vectorWeight, keywordWeight, limit);
|
|
1735
1730
|
}
|
|
1736
|
-
/**
|
|
1737
|
-
* Search in Telegram messages
|
|
1738
|
-
*/
|
|
1739
1731
|
async searchMessages(query, queryEmbedding, options = {}) {
|
|
1740
1732
|
const limit = options.limit ?? 10;
|
|
1741
|
-
const vectorWeight = options.vectorWeight ?? 0.
|
|
1742
|
-
const keywordWeight = options.keywordWeight ?? 0.
|
|
1743
|
-
const vectorResults = this.vectorEnabled ? this.vectorSearchMessages(queryEmbedding, Math.ceil(limit *
|
|
1744
|
-
const keywordResults = this.keywordSearchMessages(
|
|
1745
|
-
query,
|
|
1746
|
-
Math.ceil(limit * 1.5),
|
|
1747
|
-
options.chatId
|
|
1748
|
-
);
|
|
1733
|
+
const vectorWeight = options.vectorWeight ?? 0.5;
|
|
1734
|
+
const keywordWeight = options.keywordWeight ?? 0.5;
|
|
1735
|
+
const vectorResults = this.vectorEnabled ? this.vectorSearchMessages(queryEmbedding, Math.ceil(limit * 3), options.chatId) : [];
|
|
1736
|
+
const keywordResults = this.keywordSearchMessages(query, Math.ceil(limit * 3), options.chatId);
|
|
1749
1737
|
return this.mergeResults(vectorResults, keywordResults, vectorWeight, keywordWeight, limit);
|
|
1750
1738
|
}
|
|
1751
1739
|
vectorSearchKnowledge(embedding, limit) {
|
|
@@ -1877,10 +1865,14 @@ var HybridSearch = class {
|
|
|
1877
1865
|
byId.set(r.id, { ...r, score: keywordWeight * (r.keywordScore ?? 0) });
|
|
1878
1866
|
}
|
|
1879
1867
|
}
|
|
1880
|
-
return Array.from(byId.values()).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
1868
|
+
return Array.from(byId.values()).filter((r) => r.score >= HYBRID_SEARCH_MIN_SCORE).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
1881
1869
|
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Convert BM25 rank to normalized score.
|
|
1872
|
+
* FTS5 rank is negative; more negative = better match.
|
|
1873
|
+
*/
|
|
1882
1874
|
bm25ToScore(rank) {
|
|
1883
|
-
return 1 / (1 + Math.
|
|
1875
|
+
return 1 / (1 + Math.exp(rank));
|
|
1884
1876
|
}
|
|
1885
1877
|
};
|
|
1886
1878
|
|
|
@@ -1921,6 +1913,9 @@ var ContextBuilder = class {
|
|
|
1921
1913
|
console.warn("Knowledge search failed:", error);
|
|
1922
1914
|
}
|
|
1923
1915
|
}
|
|
1916
|
+
const recentTextsSet = new Set(
|
|
1917
|
+
recentTgMessages.filter((m) => m.text && m.text.length > 0).map((m) => m.text)
|
|
1918
|
+
);
|
|
1924
1919
|
const relevantFeed = [];
|
|
1925
1920
|
if (includeFeedHistory) {
|
|
1926
1921
|
try {
|
|
@@ -1928,10 +1923,13 @@ var ContextBuilder = class {
|
|
|
1928
1923
|
chatId,
|
|
1929
1924
|
limit: maxRelevantChunks
|
|
1930
1925
|
});
|
|
1931
|
-
|
|
1926
|
+
for (const r of feedResults) {
|
|
1927
|
+
if (!recentTextsSet.has(r.text)) {
|
|
1928
|
+
relevantFeed.push(r.text);
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1932
1931
|
if (searchAllChats) {
|
|
1933
1932
|
const globalResults = await this.hybridSearch.searchMessages(query, queryEmbedding, {
|
|
1934
|
-
// No chatId = search all chats
|
|
1935
1933
|
limit: maxRelevantChunks
|
|
1936
1934
|
});
|
|
1937
1935
|
const existingTexts = new Set(relevantFeed);
|
|
@@ -1995,6 +1993,14 @@ export {
|
|
|
1995
1993
|
getDatabase,
|
|
1996
1994
|
closeDatabase,
|
|
1997
1995
|
NoopEmbeddingProvider,
|
|
1996
|
+
fetchWithTimeout,
|
|
1997
|
+
setTonapiKey,
|
|
1998
|
+
tonapiFetch,
|
|
1999
|
+
STONFI_API_BASE_URL,
|
|
2000
|
+
GECKOTERMINAL_API_URL,
|
|
2001
|
+
COINGECKO_API_URL,
|
|
2002
|
+
OPENAI_TTS_URL,
|
|
2003
|
+
ELEVENLABS_TTS_URL,
|
|
1998
2004
|
AnthropicEmbeddingProvider,
|
|
1999
2005
|
LocalEmbeddingProvider,
|
|
2000
2006
|
CachedEmbeddingProvider,
|