teleton 0.8.2 → 0.8.3
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/dist/bootstrap-DDFVEMYI.js +128 -0
- package/dist/{chunk-XBSCYMKM.js → chunk-2ERTYRHA.js} +6 -6
- package/dist/{chunk-2IZU3REP.js → chunk-33Z47EXI.js} +139 -214
- package/dist/{chunk-HEDJCLA6.js → chunk-35MX4ZUI.js} +2 -122
- package/dist/{chunk-YOSUPUAJ.js → chunk-6OOHHJ4N.js} +1 -174
- package/dist/{chunk-GGXJLMOH.js → chunk-7MWKT67G.js} +295 -416
- package/dist/chunk-AEHTQI3H.js +142 -0
- package/dist/{chunk-7YKSXOQQ.js → chunk-AERHOXGC.js} +78 -320
- package/dist/{chunk-W25Z7CM6.js → chunk-ALKAAG4O.js} +3 -3
- package/dist/chunk-CUE4UZXR.js +129 -0
- package/dist/chunk-FUNF6H4W.js +251 -0
- package/dist/{chunk-VYKW7FMV.js → chunk-GHMXWAXI.js} +1 -1
- package/dist/{chunk-J73TA3UM.js → chunk-LVTKJQ7O.js} +7 -5
- package/dist/chunk-NVKBBTI6.js +128 -0
- package/dist/{chunk-57URFK6M.js → chunk-OIMAE24Q.js} +51 -13
- package/dist/chunk-WTDAICGT.js +175 -0
- package/dist/{chunk-55SKE6YH.js → chunk-XDZDOKIF.js} +1 -1
- package/dist/cli/index.js +42 -22
- package/dist/{client-YOOHI776.js → client-5KD25NOP.js} +4 -3
- package/dist/index.js +15 -10
- package/dist/local-IHKJFQJS.js +9 -0
- package/dist/{memory-Q6EWGK2S.js → memory-QMJRM3XJ.js} +5 -3
- package/dist/{memory-hook-WUXJNVT5.js → memory-hook-VUNWZ3NY.js} +5 -4
- package/dist/{migrate-WFU6COBN.js → migrate-5VBAP52B.js} +3 -2
- package/dist/{server-GYZXKIKU.js → server-JF6FX772.js} +39 -13
- package/dist/{server-YODFBZKG.js → server-N4T7E25M.js} +14 -10
- package/dist/{setup-server-IZBUOJRU.js → setup-server-IX3BFPPH.js} +5 -3
- package/dist/{store-7M4XV6M5.js → store-BY7S6IFN.js} +4 -3
- package/dist/{tool-index-NYH57UWP.js → tool-index-FTERJSZK.js} +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TELETON_ROOT
|
|
3
|
+
} from "./chunk-EYWNOHMJ.js";
|
|
4
|
+
import {
|
|
5
|
+
createLogger
|
|
6
|
+
} from "./chunk-NQ6FZKCE.js";
|
|
7
|
+
|
|
8
|
+
// src/memory/embeddings/local.ts
|
|
9
|
+
import { pipeline, env } from "@huggingface/transformers";
|
|
10
|
+
import { join, dirname } from "path";
|
|
11
|
+
import { mkdirSync, writeFileSync, renameSync, statSync, unlinkSync } from "fs";
|
|
12
|
+
var log = createLogger("Memory");
|
|
13
|
+
var modelCacheDir = join(TELETON_ROOT, "models");
|
|
14
|
+
try {
|
|
15
|
+
mkdirSync(modelCacheDir, { recursive: true });
|
|
16
|
+
} catch {
|
|
17
|
+
}
|
|
18
|
+
env.cacheDir = modelCacheDir;
|
|
19
|
+
var MIN_FILE_SIZES = { "onnx/model.onnx": 1e6 };
|
|
20
|
+
function isCacheFileValid(filePath, fileName) {
|
|
21
|
+
try {
|
|
22
|
+
return statSync(filePath).size >= (MIN_FILE_SIZES[fileName] ?? 1);
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function ensureModelCached(model) {
|
|
28
|
+
const files = ["config.json", "tokenizer_config.json", "tokenizer.json", "onnx/model.onnx"];
|
|
29
|
+
const baseUrl = `https://huggingface.co/${model}/resolve/main`;
|
|
30
|
+
for (const file of files) {
|
|
31
|
+
const localPath = join(modelCacheDir, model, file);
|
|
32
|
+
if (isCacheFileValid(localPath, file)) continue;
|
|
33
|
+
try {
|
|
34
|
+
unlinkSync(localPath);
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
log.info(`Downloading ${model}/${file}...`);
|
|
38
|
+
mkdirSync(dirname(localPath), { recursive: true });
|
|
39
|
+
const res = await fetch(`${baseUrl}/${file}`, { redirect: "follow" });
|
|
40
|
+
if (!res.ok) {
|
|
41
|
+
throw new Error(`Failed to download ${model}/${file}: ${res.status} ${res.statusText}`);
|
|
42
|
+
}
|
|
43
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
44
|
+
const tmpPath = localPath + ".tmp";
|
|
45
|
+
writeFileSync(tmpPath, buffer);
|
|
46
|
+
renameSync(tmpPath, localPath);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
var extractorPromise = null;
|
|
50
|
+
function getExtractor(model) {
|
|
51
|
+
if (!extractorPromise) {
|
|
52
|
+
log.info(`Loading local embedding model: ${model} (cache: ${modelCacheDir})`);
|
|
53
|
+
extractorPromise = pipeline("feature-extraction", model, {
|
|
54
|
+
dtype: "fp32",
|
|
55
|
+
// Explicit cache_dir to avoid any env race condition
|
|
56
|
+
cache_dir: modelCacheDir,
|
|
57
|
+
// Prevent pthread_setaffinity_np EINVAL on VPS/containers with restricted CPU sets.
|
|
58
|
+
// ONNX Runtime skips thread affinity when thread counts are explicit.
|
|
59
|
+
session_options: { intraOpNumThreads: 1, interOpNumThreads: 1 }
|
|
60
|
+
}).then((ext) => {
|
|
61
|
+
log.info(`Local embedding model ready`);
|
|
62
|
+
return ext;
|
|
63
|
+
}).catch((err) => {
|
|
64
|
+
log.error(`Failed to load embedding model: ${err.message}`);
|
|
65
|
+
extractorPromise = null;
|
|
66
|
+
throw err;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return extractorPromise;
|
|
70
|
+
}
|
|
71
|
+
var LocalEmbeddingProvider = class {
|
|
72
|
+
id = "local";
|
|
73
|
+
model;
|
|
74
|
+
dimensions;
|
|
75
|
+
_disabled = false;
|
|
76
|
+
constructor(config) {
|
|
77
|
+
this.model = config.model || "Xenova/all-MiniLM-L6-v2";
|
|
78
|
+
this.dimensions = 384;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Pre-download and load the model at startup.
|
|
82
|
+
* If loading fails, retries once then marks provider as disabled (FTS5-only).
|
|
83
|
+
* Call this once during app init — avoids retry spam on every message.
|
|
84
|
+
*/
|
|
85
|
+
async warmup() {
|
|
86
|
+
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
87
|
+
try {
|
|
88
|
+
await ensureModelCached(this.model);
|
|
89
|
+
await getExtractor(this.model);
|
|
90
|
+
return true;
|
|
91
|
+
} catch {
|
|
92
|
+
if (attempt === 1) {
|
|
93
|
+
log.warn(`Embedding model load failed (attempt 1), retrying...`);
|
|
94
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
95
|
+
} else {
|
|
96
|
+
log.warn(
|
|
97
|
+
`Local embedding model unavailable \u2014 falling back to FTS5-only search (no vector embeddings)`
|
|
98
|
+
);
|
|
99
|
+
this._disabled = true;
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
async embedQuery(text) {
|
|
107
|
+
if (this._disabled) return [];
|
|
108
|
+
const extractor = await getExtractor(this.model);
|
|
109
|
+
const output = await extractor(text, { pooling: "mean", normalize: true });
|
|
110
|
+
return Array.from(output.data);
|
|
111
|
+
}
|
|
112
|
+
async embedBatch(texts) {
|
|
113
|
+
if (this._disabled) return [];
|
|
114
|
+
if (texts.length === 0) return [];
|
|
115
|
+
const extractor = await getExtractor(this.model);
|
|
116
|
+
const output = await extractor(texts, { pooling: "mean", normalize: true });
|
|
117
|
+
const data = output.data;
|
|
118
|
+
const dims = this.dimensions;
|
|
119
|
+
const results = [];
|
|
120
|
+
for (let i = 0; i < texts.length; i++) {
|
|
121
|
+
results.push(Array.from(data.slice(i * dims, (i + 1) * dims)));
|
|
122
|
+
}
|
|
123
|
+
return results;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
LocalEmbeddingProvider
|
|
129
|
+
};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import {
|
|
2
|
+
COINGECKO_API_URL,
|
|
3
|
+
tonapiFetch
|
|
4
|
+
} from "./chunk-VFA7QMCZ.js";
|
|
5
|
+
import {
|
|
6
|
+
fetchWithTimeout
|
|
7
|
+
} from "./chunk-XQUHC3JZ.js";
|
|
8
|
+
import {
|
|
9
|
+
TELETON_ROOT
|
|
10
|
+
} from "./chunk-EYWNOHMJ.js";
|
|
11
|
+
import {
|
|
12
|
+
createLogger
|
|
13
|
+
} from "./chunk-NQ6FZKCE.js";
|
|
14
|
+
|
|
15
|
+
// src/ton/endpoint.ts
|
|
16
|
+
var ENDPOINT_CACHE_TTL_MS = 6e4;
|
|
17
|
+
var ORBS_HOST = "ton.access.orbs.network";
|
|
18
|
+
var ORBS_TOPOLOGY_URL = `https://${ORBS_HOST}/mngr/nodes?npm_version=2.3.3`;
|
|
19
|
+
var TONCENTER_URL = `https://toncenter.com/api/v2/jsonRPC`;
|
|
20
|
+
var _cache = null;
|
|
21
|
+
var _toncenterApiKey;
|
|
22
|
+
function setToncenterApiKey(key) {
|
|
23
|
+
_toncenterApiKey = key;
|
|
24
|
+
}
|
|
25
|
+
function getToncenterApiKey() {
|
|
26
|
+
return _toncenterApiKey;
|
|
27
|
+
}
|
|
28
|
+
async function discoverOrbsEndpoint() {
|
|
29
|
+
const res = await fetch(ORBS_TOPOLOGY_URL, { signal: AbortSignal.timeout(5e3) });
|
|
30
|
+
const nodes = await res.json();
|
|
31
|
+
const healthy = nodes.filter(
|
|
32
|
+
(n) => n.Healthy === "1" && n.Weight > 0 && n.Mngr?.health?.["v2-mainnet"]
|
|
33
|
+
);
|
|
34
|
+
if (healthy.length === 0) throw new Error("no healthy orbs nodes");
|
|
35
|
+
const totalWeight = healthy.reduce((sum, n) => sum + n.Weight, 0);
|
|
36
|
+
let r = Math.floor(Math.random() * totalWeight);
|
|
37
|
+
let chosen = healthy[0];
|
|
38
|
+
for (const node of healthy) {
|
|
39
|
+
r -= node.Weight;
|
|
40
|
+
if (r < 0) {
|
|
41
|
+
chosen = node;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return `https://${ORBS_HOST}/${chosen.NodeId}/1/mainnet/toncenter-api-v2/jsonRPC`;
|
|
46
|
+
}
|
|
47
|
+
async function getCachedHttpEndpoint() {
|
|
48
|
+
if (_cache && Date.now() - _cache.ts < ENDPOINT_CACHE_TTL_MS) {
|
|
49
|
+
return _cache.url;
|
|
50
|
+
}
|
|
51
|
+
let url;
|
|
52
|
+
if (_toncenterApiKey) {
|
|
53
|
+
try {
|
|
54
|
+
const testUrl = `https://toncenter.com/api/v2/getAddressInformation?address=EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c`;
|
|
55
|
+
const res = await fetch(testUrl, {
|
|
56
|
+
headers: { "X-API-Key": _toncenterApiKey },
|
|
57
|
+
signal: AbortSignal.timeout(5e3)
|
|
58
|
+
});
|
|
59
|
+
if (!res.ok) throw new Error(`TonCenter ${res.status}`);
|
|
60
|
+
url = TONCENTER_URL;
|
|
61
|
+
} catch {
|
|
62
|
+
try {
|
|
63
|
+
url = await discoverOrbsEndpoint();
|
|
64
|
+
} catch {
|
|
65
|
+
url = TONCENTER_URL;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
try {
|
|
70
|
+
url = await discoverOrbsEndpoint();
|
|
71
|
+
} catch {
|
|
72
|
+
url = TONCENTER_URL;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
_cache = { url, ts: Date.now() };
|
|
76
|
+
return url;
|
|
77
|
+
}
|
|
78
|
+
function invalidateEndpointCache() {
|
|
79
|
+
_cache = null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/ton/wallet-service.ts
|
|
83
|
+
import { mnemonicNew, mnemonicToPrivateKey, mnemonicValidate } from "@ton/crypto";
|
|
84
|
+
import { WalletContractV5R1, TonClient, fromNano } from "@ton/ton";
|
|
85
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
86
|
+
import { join, dirname } from "path";
|
|
87
|
+
var log = createLogger("TON");
|
|
88
|
+
var WALLET_FILE = join(TELETON_ROOT, "wallet.json");
|
|
89
|
+
var _walletCache;
|
|
90
|
+
var _keyPairCache = null;
|
|
91
|
+
var _tonClientCache = null;
|
|
92
|
+
async function generateWallet() {
|
|
93
|
+
const mnemonic = await mnemonicNew(24);
|
|
94
|
+
const keyPair = await mnemonicToPrivateKey(mnemonic);
|
|
95
|
+
const wallet = WalletContractV5R1.create({
|
|
96
|
+
workchain: 0,
|
|
97
|
+
publicKey: keyPair.publicKey
|
|
98
|
+
});
|
|
99
|
+
const address = wallet.address.toString({ bounceable: true, testOnly: false });
|
|
100
|
+
return {
|
|
101
|
+
version: "w5r1",
|
|
102
|
+
address,
|
|
103
|
+
publicKey: keyPair.publicKey.toString("hex"),
|
|
104
|
+
mnemonic,
|
|
105
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function saveWallet(wallet) {
|
|
109
|
+
const dir = dirname(WALLET_FILE);
|
|
110
|
+
if (!existsSync(dir)) {
|
|
111
|
+
mkdirSync(dir, { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
writeFileSync(WALLET_FILE, JSON.stringify(wallet, null, 2), { encoding: "utf-8", mode: 384 });
|
|
114
|
+
_walletCache = void 0;
|
|
115
|
+
_keyPairCache = null;
|
|
116
|
+
}
|
|
117
|
+
function loadWallet() {
|
|
118
|
+
if (_walletCache !== void 0) return _walletCache;
|
|
119
|
+
if (!existsSync(WALLET_FILE)) {
|
|
120
|
+
_walletCache = null;
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const content = readFileSync(WALLET_FILE, "utf-8");
|
|
125
|
+
const parsed = JSON.parse(content);
|
|
126
|
+
if (!parsed.mnemonic || !Array.isArray(parsed.mnemonic) || parsed.mnemonic.length !== 24) {
|
|
127
|
+
throw new Error("Invalid wallet.json: mnemonic must be a 24-word array");
|
|
128
|
+
}
|
|
129
|
+
_walletCache = parsed;
|
|
130
|
+
return _walletCache;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
log.error({ err: error }, "Failed to load wallet");
|
|
133
|
+
_walletCache = null;
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function walletExists() {
|
|
138
|
+
return existsSync(WALLET_FILE);
|
|
139
|
+
}
|
|
140
|
+
async function importWallet(mnemonic) {
|
|
141
|
+
const valid = await mnemonicValidate(mnemonic);
|
|
142
|
+
if (!valid) {
|
|
143
|
+
throw new Error("Invalid mnemonic: words do not form a valid TON seed phrase");
|
|
144
|
+
}
|
|
145
|
+
const keyPair = await mnemonicToPrivateKey(mnemonic);
|
|
146
|
+
const wallet = WalletContractV5R1.create({
|
|
147
|
+
workchain: 0,
|
|
148
|
+
publicKey: keyPair.publicKey
|
|
149
|
+
});
|
|
150
|
+
const address = wallet.address.toString({ bounceable: true, testOnly: false });
|
|
151
|
+
return {
|
|
152
|
+
version: "w5r1",
|
|
153
|
+
address,
|
|
154
|
+
publicKey: keyPair.publicKey.toString("hex"),
|
|
155
|
+
mnemonic,
|
|
156
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function getWalletAddress() {
|
|
160
|
+
const wallet = loadWallet();
|
|
161
|
+
return wallet?.address || null;
|
|
162
|
+
}
|
|
163
|
+
async function getCachedTonClient() {
|
|
164
|
+
const endpoint = await getCachedHttpEndpoint();
|
|
165
|
+
if (_tonClientCache && _tonClientCache.endpoint === endpoint) {
|
|
166
|
+
return _tonClientCache.client;
|
|
167
|
+
}
|
|
168
|
+
const apiKey = getToncenterApiKey();
|
|
169
|
+
const client = new TonClient({ endpoint, ...apiKey && { apiKey } });
|
|
170
|
+
_tonClientCache = { client, endpoint };
|
|
171
|
+
return client;
|
|
172
|
+
}
|
|
173
|
+
function invalidateTonClientCache() {
|
|
174
|
+
_tonClientCache = null;
|
|
175
|
+
invalidateEndpointCache();
|
|
176
|
+
}
|
|
177
|
+
async function getKeyPair() {
|
|
178
|
+
if (_keyPairCache) return _keyPairCache;
|
|
179
|
+
const wallet = loadWallet();
|
|
180
|
+
if (!wallet) return null;
|
|
181
|
+
_keyPairCache = await mnemonicToPrivateKey(wallet.mnemonic);
|
|
182
|
+
return _keyPairCache;
|
|
183
|
+
}
|
|
184
|
+
async function getWalletBalance(address) {
|
|
185
|
+
try {
|
|
186
|
+
const client = await getCachedTonClient();
|
|
187
|
+
const { Address } = await import("@ton/core");
|
|
188
|
+
const addressObj = Address.parse(address);
|
|
189
|
+
const balance = await client.getBalance(addressObj);
|
|
190
|
+
const balanceFormatted = fromNano(balance);
|
|
191
|
+
return {
|
|
192
|
+
balance: balanceFormatted,
|
|
193
|
+
balanceNano: balance.toString()
|
|
194
|
+
};
|
|
195
|
+
} catch (error) {
|
|
196
|
+
log.error({ err: error }, "Failed to get balance");
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
var TON_PRICE_CACHE_TTL_MS = 3e4;
|
|
201
|
+
var _tonPriceCache = null;
|
|
202
|
+
async function getTonPrice() {
|
|
203
|
+
if (_tonPriceCache && Date.now() - _tonPriceCache.timestamp < TON_PRICE_CACHE_TTL_MS) {
|
|
204
|
+
return { ..._tonPriceCache };
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
const response = await tonapiFetch(`/rates?tokens=ton¤cies=usd`);
|
|
208
|
+
if (response.ok) {
|
|
209
|
+
const data = await response.json();
|
|
210
|
+
const price = data?.rates?.TON?.prices?.USD;
|
|
211
|
+
if (typeof price === "number" && price > 0) {
|
|
212
|
+
_tonPriceCache = { usd: price, source: "TonAPI", timestamp: Date.now() };
|
|
213
|
+
return _tonPriceCache;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
} catch {
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
const response = await fetchWithTimeout(
|
|
220
|
+
`${COINGECKO_API_URL}/simple/price?ids=the-open-network&vs_currencies=usd`
|
|
221
|
+
);
|
|
222
|
+
if (!response.ok) {
|
|
223
|
+
throw new Error(`CoinGecko API error: ${response.status}`);
|
|
224
|
+
}
|
|
225
|
+
const data = await response.json();
|
|
226
|
+
const price = data["the-open-network"]?.usd;
|
|
227
|
+
if (typeof price === "number" && price > 0) {
|
|
228
|
+
_tonPriceCache = { usd: price, source: "CoinGecko", timestamp: Date.now() };
|
|
229
|
+
return _tonPriceCache;
|
|
230
|
+
}
|
|
231
|
+
} catch (error) {
|
|
232
|
+
log.error({ err: error }, "Failed to get TON price");
|
|
233
|
+
}
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export {
|
|
238
|
+
setToncenterApiKey,
|
|
239
|
+
invalidateEndpointCache,
|
|
240
|
+
generateWallet,
|
|
241
|
+
saveWallet,
|
|
242
|
+
loadWallet,
|
|
243
|
+
walletExists,
|
|
244
|
+
importWallet,
|
|
245
|
+
getWalletAddress,
|
|
246
|
+
getCachedTonClient,
|
|
247
|
+
invalidateTonClientCache,
|
|
248
|
+
getKeyPair,
|
|
249
|
+
getWalletBalance,
|
|
250
|
+
getTonPrice
|
|
251
|
+
};
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getClaudeCodeApiKey,
|
|
3
|
-
getProviderMetadata,
|
|
4
3
|
refreshClaudeCodeApiKey
|
|
5
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WTDAICGT.js";
|
|
6
5
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "./chunk-LC4TV3KL.js";
|
|
6
|
+
getProviderMetadata
|
|
7
|
+
} from "./chunk-6OOHHJ4N.js";
|
|
10
8
|
import {
|
|
11
9
|
fetchWithTimeout
|
|
12
10
|
} from "./chunk-XQUHC3JZ.js";
|
|
11
|
+
import {
|
|
12
|
+
appendToTranscript,
|
|
13
|
+
readTranscript
|
|
14
|
+
} from "./chunk-LC4TV3KL.js";
|
|
13
15
|
import {
|
|
14
16
|
createLogger
|
|
15
17
|
} from "./chunk-NQ6FZKCE.js";
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLogger
|
|
3
|
+
} from "./chunk-NQ6FZKCE.js";
|
|
4
|
+
|
|
5
|
+
// src/agent/lifecycle.ts
|
|
6
|
+
import { EventEmitter } from "events";
|
|
7
|
+
var log = createLogger("Lifecycle");
|
|
8
|
+
var AgentLifecycle = class extends EventEmitter {
|
|
9
|
+
state = "stopped";
|
|
10
|
+
error;
|
|
11
|
+
startPromise = null;
|
|
12
|
+
stopPromise = null;
|
|
13
|
+
runningSince = null;
|
|
14
|
+
registeredStartFn = null;
|
|
15
|
+
registeredStopFn = null;
|
|
16
|
+
getState() {
|
|
17
|
+
return this.state;
|
|
18
|
+
}
|
|
19
|
+
getError() {
|
|
20
|
+
return this.error;
|
|
21
|
+
}
|
|
22
|
+
getUptime() {
|
|
23
|
+
if (this.state !== "running" || this.runningSince === null) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return Math.floor((Date.now() - this.runningSince) / 1e3);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Register the start/stop callbacks so start()/stop() can be called without args.
|
|
30
|
+
*/
|
|
31
|
+
registerCallbacks(startFn, stopFn) {
|
|
32
|
+
this.registeredStartFn = startFn;
|
|
33
|
+
this.registeredStopFn = stopFn;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Start the agent. Uses the provided callback or falls back to registered one.
|
|
37
|
+
* - No-op if already running
|
|
38
|
+
* - Returns existing promise if already starting
|
|
39
|
+
* - Throws if currently stopping
|
|
40
|
+
*/
|
|
41
|
+
async start(startFn) {
|
|
42
|
+
const fn = startFn ?? this.registeredStartFn;
|
|
43
|
+
if (!fn) {
|
|
44
|
+
throw new Error("No start function provided or registered");
|
|
45
|
+
}
|
|
46
|
+
if (this.state === "running") {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (this.state === "starting") {
|
|
50
|
+
return this.startPromise ?? Promise.resolve();
|
|
51
|
+
}
|
|
52
|
+
if (this.state === "stopping") {
|
|
53
|
+
throw new Error("Cannot start while agent is stopping");
|
|
54
|
+
}
|
|
55
|
+
this.transition("starting");
|
|
56
|
+
this.startPromise = (async () => {
|
|
57
|
+
try {
|
|
58
|
+
await fn();
|
|
59
|
+
this.error = void 0;
|
|
60
|
+
this.runningSince = Date.now();
|
|
61
|
+
this.transition("running");
|
|
62
|
+
} catch (err) {
|
|
63
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
64
|
+
this.error = message;
|
|
65
|
+
this.runningSince = null;
|
|
66
|
+
this.transition("stopped", message);
|
|
67
|
+
throw err;
|
|
68
|
+
} finally {
|
|
69
|
+
this.startPromise = null;
|
|
70
|
+
}
|
|
71
|
+
})();
|
|
72
|
+
return this.startPromise;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Stop the agent. Uses the provided callback or falls back to registered one.
|
|
76
|
+
* - No-op if already stopped
|
|
77
|
+
* - Returns existing promise if already stopping
|
|
78
|
+
* - If starting, waits for start to complete then stops
|
|
79
|
+
*/
|
|
80
|
+
async stop(stopFn) {
|
|
81
|
+
const fn = stopFn ?? this.registeredStopFn;
|
|
82
|
+
if (!fn) {
|
|
83
|
+
throw new Error("No stop function provided or registered");
|
|
84
|
+
}
|
|
85
|
+
if (this.state === "stopped") {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (this.state === "stopping") {
|
|
89
|
+
return this.stopPromise ?? Promise.resolve();
|
|
90
|
+
}
|
|
91
|
+
if (this.state === "starting" && this.startPromise) {
|
|
92
|
+
try {
|
|
93
|
+
await this.startPromise;
|
|
94
|
+
} catch {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
this.transition("stopping");
|
|
99
|
+
this.stopPromise = (async () => {
|
|
100
|
+
try {
|
|
101
|
+
await fn();
|
|
102
|
+
} catch (err) {
|
|
103
|
+
log.error({ err }, "Error during agent stop");
|
|
104
|
+
} finally {
|
|
105
|
+
this.runningSince = null;
|
|
106
|
+
this.transition("stopped");
|
|
107
|
+
this.stopPromise = null;
|
|
108
|
+
}
|
|
109
|
+
})();
|
|
110
|
+
return this.stopPromise;
|
|
111
|
+
}
|
|
112
|
+
transition(newState, error) {
|
|
113
|
+
this.state = newState;
|
|
114
|
+
const event = {
|
|
115
|
+
state: newState,
|
|
116
|
+
timestamp: Date.now()
|
|
117
|
+
};
|
|
118
|
+
if (error !== void 0) {
|
|
119
|
+
event.error = error;
|
|
120
|
+
}
|
|
121
|
+
log.info(`Agent state: ${newState}${error ? ` (${error})` : ""}`);
|
|
122
|
+
this.emit("stateChange", event);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
AgentLifecycle
|
|
128
|
+
};
|
|
@@ -2,26 +2,30 @@ import {
|
|
|
2
2
|
getModelsForProvider
|
|
3
3
|
} from "./chunk-WFTC3JJW.js";
|
|
4
4
|
import {
|
|
5
|
-
ConfigSchema,
|
|
6
|
-
DealsConfigSchema,
|
|
7
|
-
ensureWorkspace,
|
|
8
5
|
generateWallet,
|
|
9
6
|
getWalletAddress,
|
|
10
7
|
importWallet,
|
|
11
|
-
isNewWorkspace,
|
|
12
8
|
saveWallet,
|
|
13
9
|
walletExists
|
|
14
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-FUNF6H4W.js";
|
|
11
|
+
import {
|
|
12
|
+
ConfigSchema,
|
|
13
|
+
DealsConfigSchema,
|
|
14
|
+
ensureWorkspace,
|
|
15
|
+
isNewWorkspace
|
|
16
|
+
} from "./chunk-AERHOXGC.js";
|
|
17
|
+
import {
|
|
18
|
+
TELEGRAM_MAX_MESSAGE_LENGTH
|
|
19
|
+
} from "./chunk-C4NKJT2Z.js";
|
|
15
20
|
import {
|
|
16
21
|
getClaudeCodeApiKey,
|
|
22
|
+
isClaudeCodeTokenValid
|
|
23
|
+
} from "./chunk-WTDAICGT.js";
|
|
24
|
+
import {
|
|
17
25
|
getProviderMetadata,
|
|
18
26
|
getSupportedProviders,
|
|
19
|
-
isClaudeCodeTokenValid,
|
|
20
27
|
validateApiKeyFormat
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import {
|
|
23
|
-
TELEGRAM_MAX_MESSAGE_LENGTH
|
|
24
|
-
} from "./chunk-C4NKJT2Z.js";
|
|
28
|
+
} from "./chunk-6OOHHJ4N.js";
|
|
25
29
|
import {
|
|
26
30
|
fetchWithTimeout
|
|
27
31
|
} from "./chunk-XQUHC3JZ.js";
|
|
@@ -34,7 +38,7 @@ import {
|
|
|
34
38
|
|
|
35
39
|
// src/webui/routes/setup.ts
|
|
36
40
|
import { Hono } from "hono";
|
|
37
|
-
import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
41
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2, statSync } from "fs";
|
|
38
42
|
import { join as join2 } from "path";
|
|
39
43
|
import YAML from "yaml";
|
|
40
44
|
|
|
@@ -386,7 +390,7 @@ function maskKey(key) {
|
|
|
386
390
|
if (key.length <= 10) return "***";
|
|
387
391
|
return key.slice(0, 6) + "..." + key.slice(-4);
|
|
388
392
|
}
|
|
389
|
-
function createSetupRoutes() {
|
|
393
|
+
function createSetupRoutes(options) {
|
|
390
394
|
const app = new Hono();
|
|
391
395
|
const authManager = new TelegramAuthManager();
|
|
392
396
|
app.get("/status", async (c) => {
|
|
@@ -744,6 +748,33 @@ function createSetupRoutes() {
|
|
|
744
748
|
);
|
|
745
749
|
}
|
|
746
750
|
});
|
|
751
|
+
app.post("/embeddings/warmup", async (c) => {
|
|
752
|
+
try {
|
|
753
|
+
const { LocalEmbeddingProvider } = await import("./local-IHKJFQJS.js");
|
|
754
|
+
const provider = new LocalEmbeddingProvider({});
|
|
755
|
+
const success = await provider.warmup();
|
|
756
|
+
return c.json({
|
|
757
|
+
success,
|
|
758
|
+
model: provider.model,
|
|
759
|
+
dimensions: provider.dimensions
|
|
760
|
+
});
|
|
761
|
+
} catch (error) {
|
|
762
|
+
return c.json(
|
|
763
|
+
{ success: false, error: error instanceof Error ? error.message : String(error) },
|
|
764
|
+
500
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
app.get("/embeddings/status", (c) => {
|
|
769
|
+
const model = "Xenova/all-MiniLM-L6-v2";
|
|
770
|
+
const modelPath = join2(TELETON_ROOT, "models", model, "onnx", "model.onnx");
|
|
771
|
+
try {
|
|
772
|
+
const stats = statSync(modelPath);
|
|
773
|
+
return c.json({ cached: true, model, modelPath, sizeBytes: stats.size });
|
|
774
|
+
} catch {
|
|
775
|
+
return c.json({ cached: false, model, modelPath });
|
|
776
|
+
}
|
|
777
|
+
});
|
|
747
778
|
app.post("/config/save", async (c) => {
|
|
748
779
|
try {
|
|
749
780
|
const input = await c.req.json();
|
|
@@ -840,7 +871,14 @@ function createSetupRoutes() {
|
|
|
840
871
|
...input.cocoon ? { cocoon: input.cocoon } : {},
|
|
841
872
|
...input.tonapi_key ? { tonapi_key: input.tonapi_key } : {},
|
|
842
873
|
...input.toncenter_api_key ? { toncenter_api_key: input.toncenter_api_key } : {},
|
|
843
|
-
...input.tavily_api_key ? { tavily_api_key: input.tavily_api_key } : {}
|
|
874
|
+
...input.tavily_api_key ? { tavily_api_key: input.tavily_api_key } : {},
|
|
875
|
+
// Persist Management API key hash so it survives reboots
|
|
876
|
+
api: {
|
|
877
|
+
enabled: true,
|
|
878
|
+
port: 7778,
|
|
879
|
+
host: "0.0.0.0",
|
|
880
|
+
...options?.keyHash ? { key_hash: options.keyHash } : {}
|
|
881
|
+
}
|
|
844
882
|
};
|
|
845
883
|
ConfigSchema.parse(config);
|
|
846
884
|
const configPath = workspace.configPath;
|