teleton 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +239 -101
- package/dist/chunk-2QUJLHCZ.js +362 -0
- package/dist/chunk-4IPJ25HE.js +2839 -0
- package/dist/{chunk-RRB6BWU7.js → chunk-6L6KGATM.js} +1042 -3039
- package/dist/{chunk-BYTHCDZA.js → chunk-ADCMUNYU.js} +65 -496
- package/dist/chunk-D5I7GBV7.js +322 -0
- package/dist/chunk-ECSCVEQQ.js +139 -0
- package/dist/chunk-GDCODBNO.js +72 -0
- package/dist/{chunk-O4R7V5Y2.js → chunk-RO62LO6Z.js} +11 -1
- package/dist/cli/index.js +346 -22
- package/dist/index.js +7 -4
- package/dist/{memory-657W5AS6.js → memory-TVDOGQXS.js} +14 -10
- package/dist/{migrate-PMB2JVXH.js → migrate-QIEMPOMT.js} +5 -2
- package/dist/{server-BQY7CM2N.js → server-RSWVCVY3.js} +805 -26
- package/dist/{task-dependency-resolver-TRPILAHM.js → task-dependency-resolver-72DLY2HV.js} +1 -1
- package/dist/{task-executor-N7XNVK5N.js → task-executor-VXB6DAV2.js} +1 -1
- package/dist/tool-index-DKI2ZNOU.js +245 -0
- package/dist/web/assets/index-BNhrx9S1.js +67 -0
- package/dist/web/assets/index-CqrrRLOh.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +16 -16
- package/dist/chunk-5WWR4CU3.js +0 -124
- package/dist/web/assets/index-CDMbujHf.css +0 -1
- package/dist/web/assets/index-DDX8oQ2z.js +0 -67
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VOYAGE_API_URL,
|
|
3
|
+
fetchWithTimeout
|
|
4
|
+
} from "./chunk-GDCODBNO.js";
|
|
5
|
+
import {
|
|
6
|
+
EMBEDDING_CACHE_EVICTION_INTERVAL,
|
|
7
|
+
EMBEDDING_CACHE_EVICTION_RATIO,
|
|
8
|
+
EMBEDDING_CACHE_MAX_ENTRIES,
|
|
9
|
+
EMBEDDING_CACHE_TTL_DAYS,
|
|
10
|
+
VOYAGE_BATCH_SIZE
|
|
11
|
+
} from "./chunk-RO62LO6Z.js";
|
|
12
|
+
import {
|
|
13
|
+
TELETON_ROOT
|
|
14
|
+
} from "./chunk-EYWNOHMJ.js";
|
|
15
|
+
|
|
16
|
+
// src/memory/embeddings/provider.ts
|
|
17
|
+
var NoopEmbeddingProvider = class {
|
|
18
|
+
id = "noop";
|
|
19
|
+
model = "none";
|
|
20
|
+
dimensions = 0;
|
|
21
|
+
async embedQuery(_text) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
async embedBatch(_texts) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/memory/embeddings/anthropic.ts
|
|
30
|
+
var AnthropicEmbeddingProvider = class {
|
|
31
|
+
id = "anthropic";
|
|
32
|
+
model;
|
|
33
|
+
dimensions;
|
|
34
|
+
apiKey;
|
|
35
|
+
baseUrl = VOYAGE_API_URL;
|
|
36
|
+
constructor(config) {
|
|
37
|
+
this.apiKey = config.apiKey;
|
|
38
|
+
this.model = config.model ?? "voyage-3-lite";
|
|
39
|
+
const dims = {
|
|
40
|
+
"voyage-3": 1024,
|
|
41
|
+
"voyage-3-lite": 512,
|
|
42
|
+
"voyage-code-3": 1024,
|
|
43
|
+
"voyage-finance-2": 1024,
|
|
44
|
+
"voyage-multilingual-2": 1024,
|
|
45
|
+
"voyage-law-2": 1024
|
|
46
|
+
};
|
|
47
|
+
this.dimensions = dims[this.model] ?? 512;
|
|
48
|
+
}
|
|
49
|
+
async embedQuery(text) {
|
|
50
|
+
const result = await this.embed([text]);
|
|
51
|
+
return result[0] ?? [];
|
|
52
|
+
}
|
|
53
|
+
async embedBatch(texts) {
|
|
54
|
+
if (texts.length === 0) return [];
|
|
55
|
+
const batchSize = VOYAGE_BATCH_SIZE;
|
|
56
|
+
const results = [];
|
|
57
|
+
for (let i = 0; i < texts.length; i += batchSize) {
|
|
58
|
+
const batch = texts.slice(i, i + batchSize);
|
|
59
|
+
const embeddings = await this.embed(batch);
|
|
60
|
+
results.push(...embeddings);
|
|
61
|
+
}
|
|
62
|
+
return results;
|
|
63
|
+
}
|
|
64
|
+
async embed(texts) {
|
|
65
|
+
const response = await fetchWithTimeout(`${this.baseUrl}/embeddings`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: {
|
|
68
|
+
"Content-Type": "application/json",
|
|
69
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify({
|
|
72
|
+
input: texts,
|
|
73
|
+
model: this.model,
|
|
74
|
+
input_type: "document"
|
|
75
|
+
})
|
|
76
|
+
});
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
const error = await response.text();
|
|
79
|
+
throw new Error(`Voyage API error: ${response.status} ${error}`);
|
|
80
|
+
}
|
|
81
|
+
const data = await response.json();
|
|
82
|
+
return data.data.map((item) => item.embedding);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// src/memory/embeddings/local.ts
|
|
87
|
+
import { pipeline, env } from "@huggingface/transformers";
|
|
88
|
+
import { join } from "path";
|
|
89
|
+
env.cacheDir = join(TELETON_ROOT, "models");
|
|
90
|
+
var extractorPromise = null;
|
|
91
|
+
function getExtractor(model) {
|
|
92
|
+
if (!extractorPromise) {
|
|
93
|
+
console.log(`\u{1F4E6} Loading local embedding model: ${model} (cache: ${env.cacheDir})`);
|
|
94
|
+
extractorPromise = pipeline("feature-extraction", model, {
|
|
95
|
+
dtype: "fp32"
|
|
96
|
+
}).then((ext) => {
|
|
97
|
+
console.log(`\u2705 Local embedding model ready`);
|
|
98
|
+
return ext;
|
|
99
|
+
}).catch((err) => {
|
|
100
|
+
console.error(`\u274C Failed to load embedding model: ${err.message}`);
|
|
101
|
+
extractorPromise = null;
|
|
102
|
+
throw err;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return extractorPromise;
|
|
106
|
+
}
|
|
107
|
+
var LocalEmbeddingProvider = class {
|
|
108
|
+
id = "local";
|
|
109
|
+
model;
|
|
110
|
+
dimensions;
|
|
111
|
+
_disabled = false;
|
|
112
|
+
constructor(config) {
|
|
113
|
+
this.model = config.model || "Xenova/all-MiniLM-L6-v2";
|
|
114
|
+
this.dimensions = 384;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Pre-download and load the model at startup.
|
|
118
|
+
* If loading fails, marks this provider as disabled (returns empty embeddings).
|
|
119
|
+
* Call this once during app init — avoids retry spam on every message.
|
|
120
|
+
* @returns true if model loaded successfully, false if fallback to noop
|
|
121
|
+
*/
|
|
122
|
+
async warmup() {
|
|
123
|
+
try {
|
|
124
|
+
await getExtractor(this.model);
|
|
125
|
+
return true;
|
|
126
|
+
} catch (err) {
|
|
127
|
+
console.warn(
|
|
128
|
+
`\u26A0\uFE0F Local embedding model unavailable \u2014 falling back to FTS5-only search (no vector embeddings)`
|
|
129
|
+
);
|
|
130
|
+
this._disabled = true;
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async embedQuery(text) {
|
|
135
|
+
if (this._disabled) return [];
|
|
136
|
+
const extractor = await getExtractor(this.model);
|
|
137
|
+
const output = await extractor(text, { pooling: "mean", normalize: true });
|
|
138
|
+
return Array.from(output.data);
|
|
139
|
+
}
|
|
140
|
+
async embedBatch(texts) {
|
|
141
|
+
if (this._disabled) return [];
|
|
142
|
+
if (texts.length === 0) return [];
|
|
143
|
+
const extractor = await getExtractor(this.model);
|
|
144
|
+
const output = await extractor(texts, { pooling: "mean", normalize: true });
|
|
145
|
+
const data = output.data;
|
|
146
|
+
const dims = this.dimensions;
|
|
147
|
+
const results = [];
|
|
148
|
+
for (let i = 0; i < texts.length; i++) {
|
|
149
|
+
results.push(Array.from(data.slice(i * dims, (i + 1) * dims)));
|
|
150
|
+
}
|
|
151
|
+
return results;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// src/memory/embeddings/index.ts
|
|
156
|
+
import { createHash } from "crypto";
|
|
157
|
+
function createEmbeddingProvider(config) {
|
|
158
|
+
switch (config.provider) {
|
|
159
|
+
case "anthropic":
|
|
160
|
+
if (!config.apiKey) {
|
|
161
|
+
throw new Error("API key required for Anthropic embedding provider");
|
|
162
|
+
}
|
|
163
|
+
return new AnthropicEmbeddingProvider({
|
|
164
|
+
apiKey: config.apiKey,
|
|
165
|
+
model: config.model
|
|
166
|
+
});
|
|
167
|
+
case "local":
|
|
168
|
+
return new LocalEmbeddingProvider({
|
|
169
|
+
model: config.model
|
|
170
|
+
});
|
|
171
|
+
case "none":
|
|
172
|
+
return new NoopEmbeddingProvider();
|
|
173
|
+
default:
|
|
174
|
+
throw new Error(`Unknown embedding provider: ${config.provider}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function hashText(text) {
|
|
178
|
+
return createHash("sha256").update(text).digest("hex");
|
|
179
|
+
}
|
|
180
|
+
function serializeEmbedding(embedding) {
|
|
181
|
+
return Buffer.from(new Float32Array(embedding).buffer);
|
|
182
|
+
}
|
|
183
|
+
function deserializeEmbedding(data) {
|
|
184
|
+
try {
|
|
185
|
+
if (Buffer.isBuffer(data)) {
|
|
186
|
+
const floats = new Float32Array(data.buffer, data.byteOffset, data.byteLength / 4);
|
|
187
|
+
return Array.from(floats);
|
|
188
|
+
}
|
|
189
|
+
return JSON.parse(data);
|
|
190
|
+
} catch {
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/memory/embeddings/cached.ts
|
|
196
|
+
var CachedEmbeddingProvider = class {
|
|
197
|
+
constructor(inner, db) {
|
|
198
|
+
this.inner = inner;
|
|
199
|
+
this.db = db;
|
|
200
|
+
this.id = inner.id;
|
|
201
|
+
this.model = inner.model;
|
|
202
|
+
this.dimensions = inner.dimensions;
|
|
203
|
+
}
|
|
204
|
+
id;
|
|
205
|
+
model;
|
|
206
|
+
dimensions;
|
|
207
|
+
hits = 0;
|
|
208
|
+
misses = 0;
|
|
209
|
+
ops = 0;
|
|
210
|
+
cacheGet(hash) {
|
|
211
|
+
return this.db.prepare(
|
|
212
|
+
`SELECT embedding FROM embedding_cache WHERE hash = ? AND model = ? AND provider = ?`
|
|
213
|
+
).get(hash, this.model, this.id);
|
|
214
|
+
}
|
|
215
|
+
cachePut(hash, blob) {
|
|
216
|
+
this.db.prepare(
|
|
217
|
+
`INSERT OR REPLACE INTO embedding_cache (hash, embedding, model, provider, dims, created_at, accessed_at)
|
|
218
|
+
VALUES (?, ?, ?, ?, ?, unixepoch(), unixepoch())`
|
|
219
|
+
).run(hash, blob, this.model, this.id, this.dimensions);
|
|
220
|
+
}
|
|
221
|
+
cacheTouch(hash) {
|
|
222
|
+
this.db.prepare(
|
|
223
|
+
`UPDATE embedding_cache SET accessed_at = unixepoch() WHERE hash = ? AND model = ? AND provider = ?`
|
|
224
|
+
).run(hash, this.model, this.id);
|
|
225
|
+
}
|
|
226
|
+
async warmup() {
|
|
227
|
+
return this.inner.warmup?.() ?? true;
|
|
228
|
+
}
|
|
229
|
+
async embedQuery(text) {
|
|
230
|
+
const hash = hashText(text);
|
|
231
|
+
const row = this.cacheGet(hash);
|
|
232
|
+
if (row) {
|
|
233
|
+
this.hits++;
|
|
234
|
+
this.cacheTouch(hash);
|
|
235
|
+
this.tick();
|
|
236
|
+
return deserializeEmbedding(row.embedding);
|
|
237
|
+
}
|
|
238
|
+
this.misses++;
|
|
239
|
+
const embedding = await this.inner.embedQuery(text);
|
|
240
|
+
this.cachePut(hash, serializeEmbedding(embedding));
|
|
241
|
+
this.tick();
|
|
242
|
+
return embedding;
|
|
243
|
+
}
|
|
244
|
+
async embedBatch(texts) {
|
|
245
|
+
if (texts.length === 0) return [];
|
|
246
|
+
const hashes = texts.map(hashText);
|
|
247
|
+
const results = new Array(texts.length).fill(null);
|
|
248
|
+
const missIndices = [];
|
|
249
|
+
const missTexts = [];
|
|
250
|
+
for (let i = 0; i < texts.length; i++) {
|
|
251
|
+
const row = this.cacheGet(hashes[i]);
|
|
252
|
+
if (row) {
|
|
253
|
+
this.hits++;
|
|
254
|
+
this.cacheTouch(hashes[i]);
|
|
255
|
+
results[i] = deserializeEmbedding(row.embedding);
|
|
256
|
+
} else {
|
|
257
|
+
this.misses++;
|
|
258
|
+
missIndices.push(i);
|
|
259
|
+
missTexts.push(texts[i]);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (missTexts.length > 0) {
|
|
263
|
+
const newEmbeddings = await this.inner.embedBatch(missTexts);
|
|
264
|
+
for (let j = 0; j < missIndices.length; j++) {
|
|
265
|
+
const idx = missIndices[j];
|
|
266
|
+
const embedding = newEmbeddings[j] ?? [];
|
|
267
|
+
results[idx] = embedding;
|
|
268
|
+
if (embedding.length > 0) {
|
|
269
|
+
this.cachePut(hashes[idx], serializeEmbedding(embedding));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
this.ops += texts.length;
|
|
274
|
+
this.maybeEvict();
|
|
275
|
+
this.maybeLogStats();
|
|
276
|
+
return results;
|
|
277
|
+
}
|
|
278
|
+
tick() {
|
|
279
|
+
this.ops++;
|
|
280
|
+
this.maybeEvict();
|
|
281
|
+
this.maybeLogStats();
|
|
282
|
+
}
|
|
283
|
+
maybeLogStats() {
|
|
284
|
+
const total = this.hits + this.misses;
|
|
285
|
+
if (total > 0 && total % 100 === 0) {
|
|
286
|
+
const rate = (this.hits / total * 100).toFixed(0);
|
|
287
|
+
console.log(
|
|
288
|
+
`\u{1F4CA} Embedding cache: ${this.hits} hits, ${this.misses} misses (${rate}% hit rate)`
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
maybeEvict() {
|
|
293
|
+
if (this.ops % EMBEDDING_CACHE_EVICTION_INTERVAL !== 0) return;
|
|
294
|
+
try {
|
|
295
|
+
const cutoff = Math.floor(Date.now() / 1e3) - EMBEDDING_CACHE_TTL_DAYS * 86400;
|
|
296
|
+
this.db.prepare(`DELETE FROM embedding_cache WHERE accessed_at < ?`).run(cutoff);
|
|
297
|
+
const count = this.db.prepare(`SELECT COUNT(*) as cnt FROM embedding_cache`).get().cnt;
|
|
298
|
+
if (count > EMBEDDING_CACHE_MAX_ENTRIES) {
|
|
299
|
+
const toDelete = Math.ceil(count * EMBEDDING_CACHE_EVICTION_RATIO);
|
|
300
|
+
this.db.prepare(
|
|
301
|
+
`DELETE FROM embedding_cache WHERE (hash, model, provider) IN (
|
|
302
|
+
SELECT hash, model, provider FROM embedding_cache ORDER BY accessed_at ASC LIMIT ?
|
|
303
|
+
)`
|
|
304
|
+
).run(toDelete);
|
|
305
|
+
console.log(`\u{1F9F9} Embedding cache eviction: removed ${toDelete} entries (${count} total)`);
|
|
306
|
+
}
|
|
307
|
+
} catch (err) {
|
|
308
|
+
console.warn("\u26A0\uFE0F Embedding cache eviction error:", err);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
export {
|
|
314
|
+
NoopEmbeddingProvider,
|
|
315
|
+
AnthropicEmbeddingProvider,
|
|
316
|
+
LocalEmbeddingProvider,
|
|
317
|
+
CachedEmbeddingProvider,
|
|
318
|
+
createEmbeddingProvider,
|
|
319
|
+
hashText,
|
|
320
|
+
serializeEmbedding,
|
|
321
|
+
deserializeEmbedding
|
|
322
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TELETON_ROOT
|
|
3
|
+
} from "./chunk-EYWNOHMJ.js";
|
|
4
|
+
|
|
5
|
+
// src/utils/module-db.ts
|
|
6
|
+
import Database from "better-sqlite3";
|
|
7
|
+
import { existsSync, mkdirSync, chmodSync } from "fs";
|
|
8
|
+
import { dirname, join } from "path";
|
|
9
|
+
var JOURNAL_SCHEMA = `
|
|
10
|
+
CREATE TABLE IF NOT EXISTS journal (
|
|
11
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
12
|
+
timestamp INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
13
|
+
type TEXT NOT NULL CHECK(type IN ('trade', 'gift', 'middleman', 'kol')),
|
|
14
|
+
action TEXT NOT NULL,
|
|
15
|
+
asset_from TEXT,
|
|
16
|
+
asset_to TEXT,
|
|
17
|
+
amount_from REAL,
|
|
18
|
+
amount_to REAL,
|
|
19
|
+
price_ton REAL,
|
|
20
|
+
counterparty TEXT,
|
|
21
|
+
platform TEXT,
|
|
22
|
+
reasoning TEXT,
|
|
23
|
+
outcome TEXT CHECK(outcome IN ('pending', 'profit', 'loss', 'neutral', 'cancelled')),
|
|
24
|
+
pnl_ton REAL,
|
|
25
|
+
pnl_pct REAL,
|
|
26
|
+
tx_hash TEXT,
|
|
27
|
+
tool_used TEXT,
|
|
28
|
+
chat_id TEXT,
|
|
29
|
+
user_id INTEGER,
|
|
30
|
+
closed_at INTEGER,
|
|
31
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_journal_type ON journal(type);
|
|
35
|
+
CREATE INDEX IF NOT EXISTS idx_journal_timestamp ON journal(timestamp DESC);
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_journal_asset_from ON journal(asset_from);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_journal_outcome ON journal(outcome);
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_journal_type_timestamp ON journal(type, timestamp DESC);
|
|
39
|
+
`;
|
|
40
|
+
var USED_TRANSACTIONS_SCHEMA = `
|
|
41
|
+
CREATE TABLE IF NOT EXISTS used_transactions (
|
|
42
|
+
tx_hash TEXT PRIMARY KEY,
|
|
43
|
+
user_id TEXT NOT NULL,
|
|
44
|
+
amount REAL NOT NULL,
|
|
45
|
+
game_type TEXT NOT NULL,
|
|
46
|
+
used_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_used_tx_user ON used_transactions(user_id);
|
|
50
|
+
CREATE INDEX IF NOT EXISTS idx_used_tx_used_at ON used_transactions(used_at);
|
|
51
|
+
`;
|
|
52
|
+
function openModuleDb(path) {
|
|
53
|
+
const dir = dirname(path);
|
|
54
|
+
if (!existsSync(dir)) {
|
|
55
|
+
mkdirSync(dir, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
const db = new Database(path);
|
|
58
|
+
try {
|
|
59
|
+
chmodSync(path, 384);
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
db.pragma("journal_mode = WAL");
|
|
63
|
+
return db;
|
|
64
|
+
}
|
|
65
|
+
function createDbWrapper(getDb, moduleName) {
|
|
66
|
+
return function withDb(executor) {
|
|
67
|
+
return (params, context) => {
|
|
68
|
+
const moduleDb = getDb();
|
|
69
|
+
if (!moduleDb) {
|
|
70
|
+
return Promise.resolve({
|
|
71
|
+
success: false,
|
|
72
|
+
error: `${moduleName} module not started`
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return executor(params, { ...context, db: moduleDb });
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
var MAIN_DB_PATH = join(TELETON_ROOT, "memory.db");
|
|
80
|
+
function migrateFromMainDb(moduleDb, tables) {
|
|
81
|
+
let totalMigrated = 0;
|
|
82
|
+
for (const table of tables) {
|
|
83
|
+
if (!/^[a-z_]+$/.test(table)) {
|
|
84
|
+
throw new Error(`Invalid table name for migration: "${table}"`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
for (const table of tables) {
|
|
88
|
+
try {
|
|
89
|
+
const row = moduleDb.prepare(`SELECT COUNT(*) as c FROM ${table}`).get();
|
|
90
|
+
if (row.c > 0) return 0;
|
|
91
|
+
} catch {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!existsSync(MAIN_DB_PATH)) return 0;
|
|
96
|
+
try {
|
|
97
|
+
moduleDb.exec(`ATTACH DATABASE '${MAIN_DB_PATH}' AS main_db`);
|
|
98
|
+
for (const table of tables) {
|
|
99
|
+
try {
|
|
100
|
+
const exists = moduleDb.prepare(`SELECT name FROM main_db.sqlite_master WHERE type='table' AND name=?`).get(table);
|
|
101
|
+
if (!exists) continue;
|
|
102
|
+
const src = moduleDb.prepare(`SELECT COUNT(*) as c FROM main_db.${table}`).get();
|
|
103
|
+
if (src.c === 0) continue;
|
|
104
|
+
const dstCols = moduleDb.prepare(`PRAGMA table_info(${table})`).all().map((r) => r.name);
|
|
105
|
+
const srcCols = moduleDb.prepare(`PRAGMA main_db.table_info(${table})`).all().map((r) => r.name);
|
|
106
|
+
const shared = dstCols.filter((c) => srcCols.includes(c));
|
|
107
|
+
if (shared.length === 0) continue;
|
|
108
|
+
const cols = shared.join(", ");
|
|
109
|
+
moduleDb.exec(
|
|
110
|
+
`INSERT OR IGNORE INTO ${table} (${cols}) SELECT ${cols} FROM main_db.${table}`
|
|
111
|
+
);
|
|
112
|
+
totalMigrated += src.c;
|
|
113
|
+
try {
|
|
114
|
+
moduleDb.exec(`DROP TABLE main_db.${table}`);
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
console.log(` \u{1F4E6} Migrated ${src.c} rows from memory.db \u2192 ${table} (source dropped)`);
|
|
118
|
+
} catch (e) {
|
|
119
|
+
console.warn(` \u26A0\uFE0F Could not migrate table ${table}:`, e);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
moduleDb.exec(`DETACH DATABASE main_db`);
|
|
123
|
+
} catch (e) {
|
|
124
|
+
console.warn(`\u26A0\uFE0F Migration from memory.db failed:`, e);
|
|
125
|
+
try {
|
|
126
|
+
moduleDb.exec(`DETACH DATABASE main_db`);
|
|
127
|
+
} catch {
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return totalMigrated;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export {
|
|
134
|
+
JOURNAL_SCHEMA,
|
|
135
|
+
USED_TRANSACTIONS_SCHEMA,
|
|
136
|
+
openModuleDb,
|
|
137
|
+
createDbWrapper,
|
|
138
|
+
migrateFromMainDb
|
|
139
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_FETCH_TIMEOUT_MS
|
|
3
|
+
} from "./chunk-4DU3C27M.js";
|
|
4
|
+
|
|
5
|
+
// src/utils/fetch.ts
|
|
6
|
+
var DEFAULT_TIMEOUT_MS = DEFAULT_FETCH_TIMEOUT_MS;
|
|
7
|
+
function fetchWithTimeout(url, init) {
|
|
8
|
+
const { timeoutMs = DEFAULT_TIMEOUT_MS, ...fetchInit } = init ?? {};
|
|
9
|
+
if (fetchInit.signal) {
|
|
10
|
+
return fetch(url, fetchInit);
|
|
11
|
+
}
|
|
12
|
+
return fetch(url, {
|
|
13
|
+
...fetchInit,
|
|
14
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/constants/api-endpoints.ts
|
|
19
|
+
var TONAPI_BASE_URL = "https://tonapi.io/v2";
|
|
20
|
+
var _tonapiKey;
|
|
21
|
+
function setTonapiKey(key) {
|
|
22
|
+
_tonapiKey = key;
|
|
23
|
+
}
|
|
24
|
+
function tonapiHeaders() {
|
|
25
|
+
const headers = { Accept: "application/json" };
|
|
26
|
+
if (_tonapiKey) {
|
|
27
|
+
headers["Authorization"] = `Bearer ${_tonapiKey}`;
|
|
28
|
+
}
|
|
29
|
+
return headers;
|
|
30
|
+
}
|
|
31
|
+
var TONAPI_MAX_RPS = 5;
|
|
32
|
+
var _tonapiTimestamps = [];
|
|
33
|
+
async function waitForTonapiSlot() {
|
|
34
|
+
const clean = () => {
|
|
35
|
+
const cutoff = Date.now() - 1e3;
|
|
36
|
+
while (_tonapiTimestamps.length > 0 && _tonapiTimestamps[0] <= cutoff) {
|
|
37
|
+
_tonapiTimestamps.shift();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
clean();
|
|
41
|
+
if (_tonapiTimestamps.length >= TONAPI_MAX_RPS) {
|
|
42
|
+
const waitMs = _tonapiTimestamps[0] + 1e3 - Date.now() + 50;
|
|
43
|
+
if (waitMs > 0) await new Promise((r) => setTimeout(r, waitMs));
|
|
44
|
+
clean();
|
|
45
|
+
}
|
|
46
|
+
_tonapiTimestamps.push(Date.now());
|
|
47
|
+
}
|
|
48
|
+
async function tonapiFetch(path, init) {
|
|
49
|
+
await waitForTonapiSlot();
|
|
50
|
+
return fetchWithTimeout(`${TONAPI_BASE_URL}${path}`, {
|
|
51
|
+
...init,
|
|
52
|
+
headers: { ...tonapiHeaders(), ...init?.headers }
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
var STONFI_API_BASE_URL = "https://api.ston.fi/v1";
|
|
56
|
+
var GECKOTERMINAL_API_URL = "https://api.geckoterminal.com/api/v2";
|
|
57
|
+
var COINGECKO_API_URL = "https://api.coingecko.com/api/v3";
|
|
58
|
+
var OPENAI_TTS_URL = "https://api.openai.com/v1/audio/speech";
|
|
59
|
+
var ELEVENLABS_TTS_URL = "https://api.elevenlabs.io/v1/text-to-speech";
|
|
60
|
+
var VOYAGE_API_URL = "https://api.voyageai.com/v1";
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
fetchWithTimeout,
|
|
64
|
+
setTonapiKey,
|
|
65
|
+
tonapiFetch,
|
|
66
|
+
STONFI_API_BASE_URL,
|
|
67
|
+
GECKOTERMINAL_API_URL,
|
|
68
|
+
COINGECKO_API_URL,
|
|
69
|
+
OPENAI_TTS_URL,
|
|
70
|
+
ELEVENLABS_TTS_URL,
|
|
71
|
+
VOYAGE_API_URL
|
|
72
|
+
};
|
|
@@ -50,6 +50,11 @@ var SESSION_SLUG_RECENT_MESSAGES = 10;
|
|
|
50
50
|
var SESSION_SLUG_MAX_TOKENS = 50;
|
|
51
51
|
var MASKING_KEEP_RECENT_COUNT = 10;
|
|
52
52
|
var EMBEDDING_CACHE_EVICTION_RATIO = 0.1;
|
|
53
|
+
var WEB_FETCH_MAX_TEXT_LENGTH = 2e4;
|
|
54
|
+
var WEB_SEARCH_MAX_RESULTS = 10;
|
|
55
|
+
var TOOL_RAG_MIN_SCORE = 0.1;
|
|
56
|
+
var TOOL_RAG_VECTOR_WEIGHT = 0.6;
|
|
57
|
+
var TOOL_RAG_KEYWORD_WEIGHT = 0.4;
|
|
53
58
|
|
|
54
59
|
export {
|
|
55
60
|
MAX_TOOL_RESULT_SIZE,
|
|
@@ -102,5 +107,10 @@ export {
|
|
|
102
107
|
SESSION_SLUG_RECENT_MESSAGES,
|
|
103
108
|
SESSION_SLUG_MAX_TOKENS,
|
|
104
109
|
MASKING_KEEP_RECENT_COUNT,
|
|
105
|
-
EMBEDDING_CACHE_EVICTION_RATIO
|
|
110
|
+
EMBEDDING_CACHE_EVICTION_RATIO,
|
|
111
|
+
WEB_FETCH_MAX_TEXT_LENGTH,
|
|
112
|
+
WEB_SEARCH_MAX_RESULTS,
|
|
113
|
+
TOOL_RAG_MIN_SCORE,
|
|
114
|
+
TOOL_RAG_VECTOR_WEIGHT,
|
|
115
|
+
TOOL_RAG_KEYWORD_WEIGHT
|
|
106
116
|
};
|