teleton 0.8.4 → 0.8.6

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.
Files changed (84) hide show
  1. package/README.md +40 -17
  2. package/dist/{bootstrap-NNEI3Z5H.js → bootstrap-PFBH6ALD.js} +11 -8
  3. package/dist/bridge-guards-HZTNH7IB.js +9 -0
  4. package/dist/{chunk-NH2CNRKJ.js → chunk-2UUGRY5B.js} +151 -159
  5. package/dist/{chunk-UMUONAD6.js → chunk-4MFN75ZK.js} +5941 -2716
  6. package/dist/{chunk-LC4TV3KL.js → chunk-4MG2AROG.js} +5 -7
  7. package/dist/{chunk-LZQOX6YY.js → chunk-6IFNQWIM.js} +7714 -8748
  8. package/dist/chunk-7KI25UJU.js +215 -0
  9. package/dist/chunk-AX5NBEHX.js +12 -0
  10. package/dist/{chunk-5LOHRZYY.js → chunk-BLUES3FJ.js} +80 -101
  11. package/dist/{chunk-CUE4UZXR.js → chunk-BT2I3ETV.js} +3 -3
  12. package/dist/chunk-CXTZPOTA.js +107 -0
  13. package/dist/{chunk-LVTKJQ7O.js → chunk-D3GT6YIY.js} +59 -7
  14. package/dist/chunk-EKCXKL5M.js +53 -0
  15. package/dist/{chunk-XDZDOKIF.js → chunk-F6S3L3OV.js} +3 -3
  16. package/dist/{chunk-C4NKJT2Z.js → chunk-J4WDJ7XS.js} +1 -1
  17. package/dist/{chunk-G7PCW63M.js → chunk-JYF2MM5I.js} +147 -113
  18. package/dist/{chunk-NVKBBTI6.js → chunk-K3QSIIMZ.js} +9 -6
  19. package/dist/{chunk-EYWNOHMJ.js → chunk-L653KKCR.js} +1 -0
  20. package/dist/chunk-OMQIAWEU.js +273 -0
  21. package/dist/chunk-PCT7GYBP.js +274 -0
  22. package/dist/chunk-QYZBWU2D.js +139 -0
  23. package/dist/{chunk-WTDAICGT.js → chunk-R6W4DJRK.js} +7 -7
  24. package/dist/{chunk-5SEMA47R.js → chunk-RILOEIK6.js} +1 -1
  25. package/dist/{chunk-6OOHHJ4N.js → chunk-TFTNZZDH.js} +20 -20
  26. package/dist/chunk-TTOZCZWE.js +96 -0
  27. package/dist/chunk-UJ54YT2T.js +12 -0
  28. package/dist/{chunk-GHMXWAXI.js → chunk-ULVL2W3D.js} +211 -445
  29. package/dist/{chunk-NQ6FZKCE.js → chunk-V3S3NXBQ.js} +3 -1
  30. package/dist/{chunk-H7MFXJZK.js → chunk-WSL4KIOI.js} +31 -26
  31. package/dist/{chunk-35MX4ZUI.js → chunk-Z5WY7BSB.js} +5 -5
  32. package/dist/{chunk-ALKAAG4O.js → chunk-ZGKE3OTA.js} +112 -49
  33. package/dist/{chunk-JROBTXWY.js → chunk-ZHRDETCX.js} +38 -4
  34. package/dist/cli/index.d.ts +2 -0
  35. package/dist/cli/index.js +272 -159
  36. package/dist/{client-5KD25NOP.js → client-S5UIK6OG.js} +10 -8
  37. package/dist/daily-logs-3WXGYAQF.js +25 -0
  38. package/dist/{get-my-gifts-Y7EN7RK4.js → get-my-gifts-3YSYM3LI.js} +3 -2
  39. package/dist/harden-permissions-PV5SGV5D.js +100 -0
  40. package/dist/index.d.ts +923 -0
  41. package/dist/index.js +29 -20
  42. package/dist/knowledge-RRWUIO3G.js +19 -0
  43. package/dist/{local-IHKJFQJS.js → local-MSZAXWUL.js} +3 -3
  44. package/dist/mcp-loader-OELDFR63.js +15 -0
  45. package/dist/{memory-QMJRM3XJ.js → memory-6U6HGRK2.js} +23 -12
  46. package/dist/memory-hook-T7Y235KY.js +19 -0
  47. package/dist/messages-KV5ADNJB.js +17 -0
  48. package/dist/{migrate-5VBAP52B.js → migrate-AX3HOKOO.js} +10 -7
  49. package/dist/{paths-XA2RJH4S.js → paths-WMVV7ZAJ.js} +1 -1
  50. package/dist/{server-WWGVDFPW.js → server-MFRYOGHR.js} +21 -23
  51. package/dist/{server-AJCOURH7.js → server-SFLCAZFR.js} +221 -27
  52. package/dist/{setup-server-VDY64CWW.js → setup-server-YWAPKZVE.js} +26 -26
  53. package/dist/{store-BY7S6IFN.js → store-PGHQASBC.js} +11 -8
  54. package/dist/{task-dependency-resolver-L6UUMTHK.js → task-dependency-resolver-YQKADDEU.js} +24 -10
  55. package/dist/{task-executor-XBNJLUCS.js → task-executor-LWAWD225.js} +4 -4
  56. package/dist/{tool-adapter-IVX2XQJE.js → tool-adapter-VKLUZSQS.js} +1 -1
  57. package/dist/{tool-index-FTERJSZK.js → tool-index-YEWDF5CK.js} +5 -5
  58. package/dist/{transcript-IM7G25OS.js → transcript-4Y3Z2BJ3.js} +3 -3
  59. package/dist/web/assets/Config-MNxA69ib.js +1 -0
  60. package/dist/web/assets/Conversations-Dk958paA.js +1 -0
  61. package/dist/web/assets/Dashboard-dM18fGOm.js +1 -0
  62. package/dist/web/assets/Hooks-D2griQnI.js +1 -0
  63. package/dist/web/assets/Mcp-CtWNzwsz.js +1 -0
  64. package/dist/web/assets/Memory-CfLwH45G.js +1 -0
  65. package/dist/web/assets/Plugins-3hoJprFo.js +1 -0
  66. package/dist/web/assets/SearchInput-CpcETdpE.js +1 -0
  67. package/dist/web/assets/Soul-BSxE73aK.js +1 -0
  68. package/dist/web/assets/Tasks-DkCkfu3A.js +1 -0
  69. package/dist/web/assets/TelegramSettingsPanel-BRzc5G6e.js +1 -0
  70. package/dist/web/assets/Tools-Du8B8Mb4.js +1 -0
  71. package/dist/web/assets/Wallet-BLILP2Gn.js +1 -0
  72. package/dist/web/assets/Workspace-qklcXpXV.js +1 -0
  73. package/dist/web/assets/index-BwEPTTKp.js +90 -0
  74. package/dist/web/assets/index-noejUsK7.css +1 -0
  75. package/dist/web/assets/{index.es-DitvF-9H.js → index.es-DdpKlnGb.js} +1 -1
  76. package/dist/web/assets/useToolManager-tdxkKn3H.js +1 -0
  77. package/dist/web/assets/utils-CnsbSMo4.js +1 -0
  78. package/dist/web/index.html +2 -2
  79. package/package.json +7 -12
  80. package/src/templates/HEARTBEAT.md +5 -0
  81. package/dist/memory-hook-VUNWZ3NY.js +0 -19
  82. package/dist/web/assets/index-BfYCdwLI.js +0 -80
  83. package/dist/web/assets/index-DmlyQVhR.css +0 -1
  84. package/dist/{chunk-WFTC3JJW.js → chunk-3NO7QU7W.js} +1 -1
package/README.md CHANGED
@@ -15,7 +15,7 @@
15
15
 
16
16
  ---
17
17
 
18
- <p align="center">Teleton is an autonomous AI agent platform that operates as a real Telegram user account (not a bot). It thinks through an agentic loop with tool calling, remembers conversations across sessions with hybrid RAG, and natively integrates the TON blockchain: send crypto, swap on DEXs, bid on domains, verify payments - all from a chat message. It can schedule tasks to run autonomously at any time. It ships with 125+ built-in tools, supports 15 LLM providers, and exposes a Plugin SDK so you can build your own tools on top of the platform.</p>
18
+ <p align="center">Teleton is an autonomous AI agent platform that operates as a real Telegram user account (not a bot). It thinks through an agentic loop with tool calling, remembers conversations across sessions with hybrid RAG, and natively integrates the TON blockchain: send crypto, swap on DEXs, bid on domains, verify payments - all from a chat message. It can schedule tasks to run autonomously at any time. It ships with 135+ built-in tools, supports 15 LLM providers, and exposes a Plugin SDK so you can build your own tools on top of the platform.</p>
19
19
 
20
20
  ### Key Highlights
21
21
 
@@ -28,7 +28,7 @@
28
28
  <tr>
29
29
  <td align="center"><br><b><ins>TON Blockchain</ins></b><br>Wallet, jettons, DEX swaps, DNS, NFTs<br><br></td>
30
30
  <td align="center"><br><b><ins>Persistent Memory</ins></b><br>Hybrid RAG, vector + keyword, auto-compaction<br><br></td>
31
- <td align="center"><br><b><ins>125+ Built-in Tools</ins></b><br>Messaging, media, crypto, DEX, DNS, files<br><br></td>
31
+ <td align="center"><br><b><ins>135+ Built-in Tools</ins></b><br>Messaging, media, crypto, DEX, DNS, files<br><br></td>
32
32
  </tr>
33
33
  <tr>
34
34
  <td align="center"><br><b><ins>Plugin SDK</ins></b><br>Custom tools, isolated DBs, secrets, hooks<br><br></td>
@@ -45,7 +45,7 @@
45
45
 
46
46
  | Category | Tools | Description |
47
47
  | ------------- | ----- | -------------------------------------------------------------- |
48
- | Telegram | 77 | Messages, media, chats, polls, stickers, gifts, stars, stories |
48
+ | Telegram | 80 | Messages, media, chats, polls, stickers, gifts, stars, stories |
49
49
  | TON & Jettons | 15 | Wallet, send/receive, balances, prices, NFTs, DEX router |
50
50
  | STON.fi DEX | 5 | Swap, quote, search, trending, pools |
51
51
  | DeDust DEX | 5 | Swap, quote, pools, prices, token analytics |
@@ -55,6 +55,7 @@
55
55
  | Web | 2 | Search and page extraction via Tavily |
56
56
  | Workspace | 6 | Sandboxed file operations, path traversal protection |
57
57
  | Exec | 4 | Shell, files, processes (off by default, admin-only) |
58
+ | Bot | 1 | Inline bot message sending for plugin interactions |
58
59
 
59
60
  ### Advanced Capabilities
60
61
 
@@ -77,6 +78,7 @@
77
78
  | **TON Proxy** | Browse .ton domains via HTTP proxy, auto-installed |
78
79
  | **Management API** | HTTPS control plane for remote admin, bootstrap mode, lifecycle control |
79
80
  | **Sandboxed Workspace** | Path traversal protection, symlink detection, immutable configs |
81
+ | **Heartbeat** | Autonomous periodic wake-up, HEARTBEAT.md task checklist, configurable intervals |
80
82
 
81
83
  ---
82
84
 
@@ -144,6 +146,26 @@ Agent: [Displays uptime, model, tool count, wallet balance]
144
146
 
145
147
  ---
146
148
 
149
+ ## User Mode vs Bot Mode
150
+
151
+ Teleton can run as a **user account** (MTProto) or a **Telegram bot** (Bot API). Set `telegram.mode` in your config:
152
+
153
+ | | User Mode (default) | Bot Mode |
154
+ |---|---|---|
155
+ | **Auth** | Phone + api_id + api_hash | Bot token from @BotFather |
156
+ | **Protocol** | MTProto (GramJS) | Bot API (Grammy) |
157
+ | **Tools** | 135+ | 67 (11 Telegram + 56 non-Telegram) |
158
+ | **Risk** | Account ban possible | No ban risk |
159
+ | **Dialogs/History** | Full access | Not available |
160
+ | **Media sending** | All types | Photos only (v1) |
161
+ | **Inline keyboards** | Via bot_token | Native |
162
+ | **Stars/Gifts** | Full access | Not available |
163
+ | **Profile editing** | Yes | No |
164
+ | **Scheduled tasks** | Yes | Not available |
165
+ | **Setup** | `telegram.mode: "user"` | `telegram.mode: "bot"` |
166
+
167
+ ---
168
+
147
169
  ## Configuration
148
170
 
149
171
  The `teleton setup` wizard generates a fully configured `~/.teleton/config.yaml` file. Manual editing is only necessary if you want to adjust settings after the initial setup.
@@ -155,6 +177,10 @@ agent:
155
177
  model: "claude-opus-4-6"
156
178
  utility_model: "claude-haiku-4-5-20251001" # for summarization, compaction, vision
157
179
  max_agentic_iterations: 5
180
+ session_reset_policy:
181
+ daily_reset_enabled: true
182
+ daily_reset_hour: 4
183
+ idle_expiry_minutes: 1440 # 24h idle → new session
158
184
 
159
185
  telegram:
160
186
  dm_policy: "admin-only" # open | allowlist | admin-only | disabled
@@ -169,11 +195,6 @@ telegram:
169
195
  bot_token: "123456:ABC-DEF..."
170
196
  bot_username: "your_bot"
171
197
 
172
- session_reset_policy:
173
- daily_reset_enabled: true
174
- daily_reset_hour: 4
175
- idle_expiry_minutes: 1440 # 24h idle → new session
176
-
177
198
  webui: # Optional: Web dashboard
178
199
  enabled: false # Enable WebUI server
179
200
  port: 7777 # HTTP server port
@@ -289,16 +310,19 @@ Optional web dashboard, localhost only, token auth. Start with `teleton start --
289
310
  </tr>
290
311
  <tr>
291
312
  <td align="center"><br><b>Memory Search</b><br>Vector + keyword hybrid<br><br></td>
292
- <td align="center"><br><b>Live Logs</b><br>Real-time SSE streaming<br><br></td>
313
+ <td align="center"><br><b>Live Logs (in Dashboard)</b><br>Real-time SSE streaming<br><br></td>
293
314
  <td align="center"><br><b>Workspace</b><br>File browser + editor<br><br></td>
294
315
  <td align="center"><br><b>MCP Servers</b><br>Add, remove, configure<br><br></td>
295
316
  </tr>
296
317
  <tr>
297
- <td align="center"><br><b>TON Proxy</b><br>Start/stop, auto-install<br><br></td>
318
+ <td align="center"><br><b>TON Proxy (in Config)</b><br>Start/stop, auto-install<br><br></td>
298
319
  <td align="center"><br><b>Tasks</b><br>Schedule, dependencies, bulk<br><br></td>
299
320
  <td align="center"><br><b>Setup Wizard</b><br>QR code + phone auth<br><br></td>
300
321
  <td align="center"><br><b>Config</b><br>Provider switch, key validation<br><br></td>
301
322
  </tr>
323
+ <tr>
324
+ <td align="center"><br><b>Hooks</b><br>Plugin hook registrations<br><br></td>
325
+ </tr>
302
326
  </table>
303
327
 
304
328
  Auth token is printed at startup. Stored as HttpOnly cookie for 7 days. For remote access:
@@ -437,7 +461,7 @@ The SDK provides namespaced access to core services:
437
461
  | `sdk.config` | Sanitized app config (no API keys) |
438
462
  | `sdk.pluginConfig` | Plugin-specific config from `config.yaml` |
439
463
  | `sdk.log` | `info()`, `warn()`, `error()`, `debug()` |
440
- | `sdk.on()` | Register hooks: `message:receive`, `response:before/after/error`, `tool:error`, `prompt:after`, `agent:start/stop` |
464
+ | `sdk.on()` | Register hooks: `tool:before`, `tool:after`, `tool:error`, `prompt:before`, `prompt:after`, `session:start`, `session:end`, `message:receive`, `response:before`, `response:after`, `response:error`, `agent:start`, `agent:stop` |
441
465
 
442
466
  **Lifecycle hooks**: `migrate(db)`, `start(ctx)`, `stop()`, `onMessage(event)`, `onCallbackQuery(event)`
443
467
 
@@ -452,7 +476,7 @@ The SDK provides namespaced access to core services:
452
476
  | Layer | Technology |
453
477
  |-------|------------|
454
478
  | LLM | Multi-provider via [pi-ai](https://github.com/mariozechner/pi-ai) (15 providers: Anthropic, Claude Code, OpenAI, Google, xAI, Groq, OpenRouter, Moonshot, Mistral, Cerebras, ZAI, MiniMax, Hugging Face, Cocoon, Local) |
455
- | Telegram Userbot | [GramJS](https://gram.js.org/) Layer 222 fork (MTProto) |
479
+ | Telegram Userbot | [GramJS](https://gram.js.org/) Layer 223 fork (MTProto) |
456
480
  | Inline Bot | [Grammy](https://grammy.dev/) (Bot API, for deals) |
457
481
  | Blockchain | [TON SDK](https://github.com/ton-org/ton) (W5R1 wallet) |
458
482
  | DeFi | STON.fi SDK, DeDust SDK |
@@ -460,7 +484,6 @@ The SDK provides namespaced access to core services:
460
484
  | Vector Search | [sqlite-vec](https://github.com/asg017/sqlite-vec) (cosine similarity) |
461
485
  | Full-Text Search | SQLite FTS5 (BM25 ranking) |
462
486
  | Embeddings | [@huggingface/transformers](https://www.npmjs.com/package/@huggingface/transformers) (local ONNX) or Voyage AI |
463
- | Token Counting | [js-tiktoken](https://github.com/dqbd/tiktoken) |
464
487
  | MCP Client | [@modelcontextprotocol/sdk](https://modelcontextprotocol.io/) (stdio + SSE + Streamable HTTP) |
465
488
  | WebUI | [Hono](https://hono.dev/) (API) + React + Vite (frontend) |
466
489
  | Language | TypeScript 5.7, Node.js 20+ |
@@ -473,13 +496,13 @@ src/
473
496
  ├── agent/ # Core agent runtime
474
497
  │ ├── runtime.ts # Agentic loop (5 iterations, tool calling, masking, compaction)
475
498
  │ ├── client.ts # Multi-provider LLM client
476
- │ └── tools/ # 125+ built-in tools
477
- │ ├── register-all.ts # Central tool registration (8 categories, 121 tools)
499
+ │ └── tools/ # 135+ built-in tools
500
+ │ ├── register-all.ts # Central tool registration (9 categories)
478
501
  │ ├── registry.ts # Tool registry, scope filtering, provider limits
479
502
  │ ├── module-loader.ts # Built-in module loading (deals + exec)
480
503
  │ ├── plugin-loader.ts # External plugin discovery, validation, hot-reload
481
504
  │ ├── mcp-loader.ts # MCP client (stdio/SSE), tool discovery, lifecycle
482
- │ ├── telegram/ # Telegram operations (77 tools)
505
+ │ ├── telegram/ # Telegram operations (80 tools)
483
506
  │ ├── ton/ # TON blockchain + jettons + DEX router (15 tools)
484
507
  │ ├── stonfi/ # STON.fi DEX (5 tools)
485
508
  │ ├── dedust/ # DeDust DEX (5 tools)
@@ -549,7 +572,7 @@ src/
549
572
  ├── templates/ # Workspace template files (SOUL.md, etc.)
550
573
  └── cli/ # CLI commands (setup, config, doctor, mcp)
551
574
 
552
- web/ # React + Vite frontend (10 pages)
575
+ web/ # React + Vite frontend (11 pages)
553
576
  packages/sdk/ # Published @teleton-agent/sdk
554
577
  ```
555
578
 
@@ -1,20 +1,23 @@
1
1
  import {
2
2
  AgentLifecycle
3
- } from "./chunk-NVKBBTI6.js";
3
+ } from "./chunk-K3QSIIMZ.js";
4
4
  import {
5
5
  configExists,
6
- ensureWorkspace,
7
6
  getDefaultConfigPath
8
- } from "./chunk-NH2CNRKJ.js";
9
- import "./chunk-C4NKJT2Z.js";
10
- import "./chunk-6OOHHJ4N.js";
7
+ } from "./chunk-2UUGRY5B.js";
8
+ import "./chunk-3UFPFWYP.js";
9
+ import {
10
+ ensureWorkspace
11
+ } from "./chunk-CXTZPOTA.js";
12
+ import "./chunk-J4WDJ7XS.js";
13
+ import "./chunk-TFTNZZDH.js";
11
14
  import {
12
15
  SHUTDOWN_TIMEOUT_MS
13
16
  } from "./chunk-R4YSJ4EY.js";
14
- import "./chunk-EYWNOHMJ.js";
17
+ import "./chunk-L653KKCR.js";
15
18
  import {
16
19
  createLogger
17
- } from "./chunk-NQ6FZKCE.js";
20
+ } from "./chunk-V3S3NXBQ.js";
18
21
  import "./chunk-3RG5ZIWI.js";
19
22
 
20
23
  // src/api/bootstrap.ts
@@ -42,7 +45,7 @@ async function startApiOnly(options) {
42
45
  marketplace: null,
43
46
  userHookEvaluator: null
44
47
  };
45
- const { ApiServer } = await import("./server-WWGVDFPW.js");
48
+ const { ApiServer } = await import("./server-MFRYOGHR.js");
46
49
  const apiConfig = {
47
50
  enabled: true,
48
51
  port: parseInt(options.apiPort || process.env.TELETON_API_PORT || "7778"),
@@ -0,0 +1,9 @@
1
+ import {
2
+ isBotBridge,
3
+ isUserBridge
4
+ } from "./chunk-UJ54YT2T.js";
5
+ import "./chunk-3RG5ZIWI.js";
6
+ export {
7
+ isBotBridge,
8
+ isUserBridge
9
+ };
@@ -1,17 +1,15 @@
1
1
  import {
2
2
  TELEGRAM_MAX_MESSAGE_LENGTH
3
- } from "./chunk-C4NKJT2Z.js";
3
+ } from "./chunk-J4WDJ7XS.js";
4
4
  import {
5
5
  getProviderMetadata
6
- } from "./chunk-6OOHHJ4N.js";
6
+ } from "./chunk-TFTNZZDH.js";
7
7
  import {
8
- TELETON_ROOT,
9
- WORKSPACE_PATHS,
10
- WORKSPACE_ROOT
11
- } from "./chunk-EYWNOHMJ.js";
8
+ TELETON_ROOT
9
+ } from "./chunk-L653KKCR.js";
12
10
  import {
13
11
  createLogger
14
- } from "./chunk-NQ6FZKCE.js";
12
+ } from "./chunk-V3S3NXBQ.js";
15
13
 
16
14
  // src/config/loader.ts
17
15
  import { readFileSync, existsSync, writeFileSync, mkdirSync } from "fs";
@@ -55,12 +53,14 @@ var AgentConfigSchema = z.object({
55
53
  temperature: z.number().default(0.7),
56
54
  system_prompt: z.string().nullable().default(null),
57
55
  max_agentic_iterations: z.number().default(5).describe("Maximum number of agentic loop iterations (tool call \u2192 result \u2192 tool call cycles)"),
56
+ toolset: z.string().default("full").describe("Active toolset profile: minimal, standard, trading, full"),
58
57
  session_reset_policy: SessionResetPolicySchema.default(SessionResetPolicySchema.parse({}))
59
58
  });
60
59
  var TelegramConfigSchema = z.object({
61
- api_id: z.number(),
62
- api_hash: z.string(),
63
- phone: z.string(),
60
+ mode: z.enum(["user", "bot"]).default("user"),
61
+ api_id: z.number().optional(),
62
+ api_hash: z.string().optional(),
63
+ phone: z.string().optional(),
64
64
  session_name: z.string().default("teleton_session"),
65
65
  session_path: z.string().default("~/.teleton"),
66
66
  dm_policy: DMPolicy.default("allowlist"),
@@ -79,7 +79,45 @@ var TelegramConfigSchema = z.object({
79
79
  owner_id: z.number().optional().describe("Owner's Telegram user ID"),
80
80
  debounce_ms: z.number().default(1500).describe("Debounce delay in milliseconds for group messages (0 = disabled)"),
81
81
  bot_token: z.string().optional().describe("Telegram Bot token from @BotFather for inline deal buttons"),
82
- bot_username: z.string().optional().describe("Bot username without @ (e.g., 'teleton_deals_bot')")
82
+ bot_username: z.string().optional().describe("Bot username without @ (e.g., 'teleton_deals_bot')"),
83
+ stream_mode: z.enum(["all", "replace", "off"]).default("replace").describe(
84
+ "Bot streaming mode: replace=each iteration replaces draft (default), all=concatenate all iterations, off=no streaming"
85
+ )
86
+ }).superRefine((data, ctx) => {
87
+ if (data.mode === "user") {
88
+ if (!data.api_id)
89
+ ctx.addIssue({
90
+ code: z.ZodIssueCode.custom,
91
+ message: "api_id is required in user mode",
92
+ path: ["api_id"]
93
+ });
94
+ if (!data.api_hash)
95
+ ctx.addIssue({
96
+ code: z.ZodIssueCode.custom,
97
+ message: "api_hash is required in user mode",
98
+ path: ["api_hash"]
99
+ });
100
+ if (!data.phone)
101
+ ctx.addIssue({
102
+ code: z.ZodIssueCode.custom,
103
+ message: "phone is required in user mode",
104
+ path: ["phone"]
105
+ });
106
+ }
107
+ if (data.mode === "bot") {
108
+ if (!data.bot_token)
109
+ ctx.addIssue({
110
+ code: z.ZodIssueCode.custom,
111
+ message: "bot_token is required in bot mode",
112
+ path: ["bot_token"]
113
+ });
114
+ if (!data.owner_id)
115
+ ctx.addIssue({
116
+ code: z.ZodIssueCode.custom,
117
+ message: "owner_id is required in bot mode",
118
+ path: ["owner_id"]
119
+ });
120
+ }
83
121
  });
84
122
  var StorageConfigSchema = z.object({
85
123
  sessions_file: z.string().default("~/.teleton/sessions.json"),
@@ -143,7 +181,7 @@ var McpServerSchema = z.object({
143
181
  args: z.array(z.string()).optional().describe("Explicit args array (overrides command splitting)"),
144
182
  env: z.record(z.string(), z.string()).optional().describe("Environment variables for stdio server"),
145
183
  url: z.string().url().optional().describe("SSE/HTTP endpoint URL (alternative to command)"),
146
- scope: z.enum(["always", "dm-only", "group-only", "admin-only"]).default("always").describe("Tool scope"),
184
+ scope: z.enum(["always", "dm-only", "group-only", "admin-only", "open", "allowlist", "disabled"]).default("always").describe("Tool scope"),
147
185
  enabled: z.boolean().default(true).describe("Enable/disable this server")
148
186
  }).refine((s) => s.command || s.url, {
149
187
  message: "Each MCP server needs either 'command' (stdio) or 'url' (SSE/HTTP)"
@@ -154,15 +192,13 @@ var _McpObject = z.object({
154
192
  var McpConfigSchema = _McpObject.default(_McpObject.parse({}));
155
193
  var _ToolRagObject = z.object({
156
194
  enabled: z.boolean().default(true).describe("Enable semantic tool retrieval (Tool RAG)"),
157
- top_k: z.number().default(25).describe("Max tools to retrieve per LLM call"),
195
+ top_k: z.number().default(35).describe("Max tools to retrieve per LLM call"),
158
196
  always_include: z.array(z.string()).default([
159
197
  "telegram_send_message",
160
- "telegram_reply_message",
198
+ "telegram_quote_reply",
161
199
  "telegram_send_photo",
162
- "telegram_send_document",
163
200
  "journal_*",
164
- "workspace_*",
165
- "web_*"
201
+ "workspace_*"
166
202
  ]).describe("Tool name patterns always included (prefix glob with *)"),
167
203
  skip_unlimited_providers: z.boolean().default(false).describe("Skip Tool RAG for providers with no tool limit (e.g. Anthropic)")
168
204
  });
@@ -185,6 +221,13 @@ var _CapabilitiesObject = z.object({
185
221
  exec: _ExecObject.default(_ExecObject.parse({}))
186
222
  });
187
223
  var CapabilitiesConfigSchema = _CapabilitiesObject.default(_CapabilitiesObject.parse({}));
224
+ var _HeartbeatObject = z.object({
225
+ enabled: z.boolean().default(true).describe("Enable periodic heartbeat timer"),
226
+ interval_ms: z.number().min(6e4).default(36e5).describe("Heartbeat interval in milliseconds (min 60s, default 60min)"),
227
+ prompt: z.string().default("Execute your HEARTBEAT.md checklist now. Work through each item using tool calls.").describe("Prompt sent to agent on each heartbeat tick"),
228
+ self_configurable: z.boolean().default(false).describe("Allow agent to modify heartbeat config via config_set")
229
+ });
230
+ var HeartbeatConfigSchema = _HeartbeatObject.default(_HeartbeatObject.parse({}));
188
231
  var ConfigSchema = z.object({
189
232
  meta: MetaConfigSchema.default(MetaConfigSchema.parse({})),
190
233
  agent: AgentConfigSchema,
@@ -199,6 +242,7 @@ var ConfigSchema = z.object({
199
242
  capabilities: CapabilitiesConfigSchema,
200
243
  api: ApiConfigSchema.optional(),
201
244
  ton_proxy: TonProxyConfigSchema,
245
+ heartbeat: HeartbeatConfigSchema,
202
246
  mcp: McpConfigSchema,
203
247
  plugins: z.record(z.string(), z.unknown()).default({}).describe("Per-plugin config (key = plugin name with underscores)"),
204
248
  cocoon: z.object({
@@ -209,8 +253,64 @@ var ConfigSchema = z.object({
209
253
  tavily_api_key: z.string().optional().describe("Tavily API key for web search & extract (free at https://tavily.com)")
210
254
  });
211
255
 
256
+ // src/config/env.ts
257
+ import { z as z2 } from "zod";
258
+ var log = createLogger("Env");
259
+ var optionalString = z2.string().optional();
260
+ var optionalInt = z2.coerce.number().int().optional();
261
+ var optionalPort = z2.coerce.number().int().min(1).max(65535).optional();
262
+ var optionalBoolean = z2.string().optional().transform(
263
+ (v) => v === "true" || v === "1" || v === "yes" ? true : v === "false" || v === "0" || v === "no" ? false : void 0
264
+ );
265
+ var envSchema = z2.object({
266
+ // Core
267
+ TELETON_HOME: optionalString,
268
+ TELETON_API_KEY: optionalString,
269
+ TELETON_BASE_URL: optionalString,
270
+ // Telegram
271
+ TELETON_TG_API_ID: optionalInt,
272
+ TELETON_TG_API_HASH: optionalString,
273
+ TELETON_TG_PHONE: optionalString,
274
+ // WebUI
275
+ TELETON_WEBUI_ENABLED: optionalBoolean,
276
+ TELETON_WEBUI_PORT: optionalPort,
277
+ TELETON_WEBUI_HOST: optionalString,
278
+ // Management API
279
+ TELETON_API_ENABLED: optionalBoolean,
280
+ TELETON_API_PORT: optionalPort,
281
+ TELETON_JSON_CREDENTIALS: optionalBoolean,
282
+ // Logging
283
+ TELETON_LOG_LEVEL: optionalString,
284
+ TELETON_LOG: optionalString,
285
+ TELETON_LOG_PRETTY: optionalString,
286
+ // External API keys
287
+ TELETON_TAVILY_API_KEY: optionalString,
288
+ TELETON_TONAPI_KEY: optionalString,
289
+ TELETON_TONCENTER_API_KEY: optionalString
290
+ });
291
+ function validateEnv() {
292
+ const result = envSchema.safeParse(process.env);
293
+ if (!result.success) {
294
+ for (const issue of result.error.issues) {
295
+ const path = issue.path.join(".");
296
+ if (path === "TELETON_TG_API_ID" && process.env.TELETON_TG_API_ID) {
297
+ throw new Error(
298
+ `Invalid TELETON_TG_API_ID environment variable: "${process.env.TELETON_TG_API_ID}" is not a valid integer`
299
+ );
300
+ }
301
+ log.warn({ path, message: issue.message }, "Invalid env var");
302
+ }
303
+ const invalidKeys = new Set(result.error.issues.map((i) => String(i.path[0])));
304
+ const cleaned = { ...process.env };
305
+ for (const key of invalidKeys) delete cleaned[key];
306
+ const retry = envSchema.safeParse(cleaned);
307
+ return retry.success ? retry.data : {};
308
+ }
309
+ return result.data;
310
+ }
311
+
212
312
  // src/config/loader.ts
213
- var log = createLogger("Config");
313
+ var log2 = createLogger("Config");
214
314
  var DEFAULT_CONFIG_PATH = join(TELETON_ROOT, "config.yaml");
215
315
  function expandPath(path) {
216
316
  if (path.startsWith("~")) {
@@ -219,6 +319,7 @@ function expandPath(path) {
219
319
  return path;
220
320
  }
221
321
  function loadConfig(configPath = DEFAULT_CONFIG_PATH) {
322
+ const env = validateEnv();
222
323
  const fullPath = expandPath(configPath);
223
324
  if (!existsSync(fullPath)) {
224
325
  throw new Error(`Config file not found: ${fullPath}
@@ -237,7 +338,7 @@ Run 'teleton setup' to create one.`);
237
338
  throw new Error(`Invalid YAML in ${fullPath}: ${error.message}`);
238
339
  }
239
340
  if (raw && typeof raw === "object" && "market" in raw) {
240
- log.warn("config.market is deprecated and ignored. Use market-api plugin instead.");
341
+ log2.warn("config.market is deprecated and ignored. Use market-api plugin instead.");
241
342
  delete raw.market;
242
343
  }
243
344
  const result = ConfigSchema.safeParse(raw);
@@ -253,71 +354,57 @@ Run 'teleton setup' to create one.`);
253
354
  config.telegram.session_path = expandPath(config.telegram.session_path);
254
355
  config.storage.sessions_file = expandPath(config.storage.sessions_file);
255
356
  config.storage.memory_file = expandPath(config.storage.memory_file);
256
- if (process.env.TELETON_API_KEY) {
257
- config.agent.api_key = process.env.TELETON_API_KEY;
357
+ if (env.TELETON_API_KEY) {
358
+ config.agent.api_key = env.TELETON_API_KEY;
258
359
  }
259
- if (process.env.TELETON_TG_API_ID) {
260
- const apiId = parseInt(process.env.TELETON_TG_API_ID, 10);
261
- if (isNaN(apiId)) {
262
- throw new Error(
263
- `Invalid TELETON_TG_API_ID environment variable: "${process.env.TELETON_TG_API_ID}" is not a valid integer`
264
- );
265
- }
266
- config.telegram.api_id = apiId;
360
+ if (env.TELETON_TG_API_ID != null) {
361
+ config.telegram.api_id = env.TELETON_TG_API_ID;
267
362
  }
268
- if (process.env.TELETON_TG_API_HASH) {
269
- config.telegram.api_hash = process.env.TELETON_TG_API_HASH;
363
+ if (env.TELETON_TG_API_HASH) {
364
+ config.telegram.api_hash = env.TELETON_TG_API_HASH;
270
365
  }
271
- if (process.env.TELETON_TG_PHONE) {
272
- config.telegram.phone = process.env.TELETON_TG_PHONE;
366
+ if (env.TELETON_TG_PHONE) {
367
+ config.telegram.phone = env.TELETON_TG_PHONE;
273
368
  }
274
- if (process.env.TELETON_WEBUI_ENABLED) {
275
- config.webui.enabled = process.env.TELETON_WEBUI_ENABLED === "true";
369
+ if (env.TELETON_WEBUI_ENABLED != null) {
370
+ config.webui.enabled = env.TELETON_WEBUI_ENABLED;
276
371
  }
277
- if (process.env.TELETON_WEBUI_PORT) {
278
- const port = parseInt(process.env.TELETON_WEBUI_PORT, 10);
279
- if (!isNaN(port) && port >= 1024 && port <= 65535) {
280
- config.webui.port = port;
281
- }
372
+ if (env.TELETON_WEBUI_PORT != null && env.TELETON_WEBUI_PORT >= 1024) {
373
+ config.webui.port = env.TELETON_WEBUI_PORT;
282
374
  }
283
- if (process.env.TELETON_WEBUI_HOST) {
284
- config.webui.host = process.env.TELETON_WEBUI_HOST;
375
+ if (env.TELETON_WEBUI_HOST) {
376
+ config.webui.host = env.TELETON_WEBUI_HOST;
285
377
  if (!["127.0.0.1", "localhost", "::1"].includes(config.webui.host)) {
286
- log.warn(
378
+ log2.warn(
287
379
  { host: config.webui.host },
288
380
  "WebUI bound to non-loopback address \u2014 ensure auth_token is set"
289
381
  );
290
382
  }
291
383
  }
292
- if (process.env.TELETON_API_ENABLED) {
384
+ if (env.TELETON_API_ENABLED != null) {
293
385
  if (!config.api) config.api = { enabled: false, port: 7778, key_hash: "", allowed_ips: [] };
294
- config.api.enabled = process.env.TELETON_API_ENABLED === "true";
386
+ config.api.enabled = env.TELETON_API_ENABLED;
295
387
  }
296
- if (process.env.TELETON_API_PORT) {
297
- const port = parseInt(process.env.TELETON_API_PORT, 10);
298
- if (!isNaN(port) && port >= 1024 && port <= 65535) {
299
- if (!config.api) config.api = { enabled: false, port: 7778, key_hash: "", allowed_ips: [] };
300
- config.api.port = port;
301
- }
388
+ if (env.TELETON_API_PORT != null && env.TELETON_API_PORT >= 1024) {
389
+ if (!config.api) config.api = { enabled: false, port: 7778, key_hash: "", allowed_ips: [] };
390
+ config.api.port = env.TELETON_API_PORT;
302
391
  }
303
- if (process.env.TELETON_BASE_URL) {
392
+ if (env.TELETON_BASE_URL) {
304
393
  try {
305
- new URL(process.env.TELETON_BASE_URL);
306
- config.agent.base_url = process.env.TELETON_BASE_URL;
394
+ new URL(env.TELETON_BASE_URL);
395
+ config.agent.base_url = env.TELETON_BASE_URL;
307
396
  } catch {
308
- throw new Error(
309
- `Invalid TELETON_BASE_URL: "${process.env.TELETON_BASE_URL}" is not a valid URL`
310
- );
397
+ throw new Error(`Invalid TELETON_BASE_URL: "${env.TELETON_BASE_URL}" is not a valid URL`);
311
398
  }
312
399
  }
313
- if (process.env.TELETON_TAVILY_API_KEY) {
314
- config.tavily_api_key = process.env.TELETON_TAVILY_API_KEY;
400
+ if (env.TELETON_TAVILY_API_KEY) {
401
+ config.tavily_api_key = env.TELETON_TAVILY_API_KEY;
315
402
  }
316
- if (process.env.TELETON_TONAPI_KEY) {
317
- config.tonapi_key = process.env.TELETON_TONAPI_KEY;
403
+ if (env.TELETON_TONAPI_KEY) {
404
+ config.tonapi_key = env.TELETON_TONAPI_KEY;
318
405
  }
319
- if (process.env.TELETON_TONCENTER_API_KEY) {
320
- config.toncenter_api_key = process.env.TELETON_TONCENTER_API_KEY;
406
+ if (env.TELETON_TONCENTER_API_KEY) {
407
+ config.toncenter_api_key = env.TELETON_TONCENTER_API_KEY;
321
408
  }
322
409
  return config;
323
410
  }
@@ -328,106 +415,11 @@ function getDefaultConfigPath() {
328
415
  return DEFAULT_CONFIG_PATH;
329
416
  }
330
417
 
331
- // src/workspace/manager.ts
332
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, copyFileSync } from "fs";
333
- import { join as join2, dirname as dirname2 } from "path";
334
- import { fileURLToPath } from "url";
335
- var log2 = createLogger("Workspace");
336
- function findPackageRoot() {
337
- let dir = dirname2(fileURLToPath(import.meta.url));
338
- for (let i = 0; i < 10; i++) {
339
- if (existsSync2(join2(dir, "package.json"))) return dir;
340
- dir = dirname2(dir);
341
- }
342
- return process.cwd();
343
- }
344
- var TEMPLATES_DIR = join2(findPackageRoot(), "src", "templates");
345
- async function ensureWorkspace(config) {
346
- const silent = config?.silent ?? false;
347
- if (!existsSync2(TELETON_ROOT)) {
348
- mkdirSync2(TELETON_ROOT, { recursive: true });
349
- if (!silent) log2.info(`Created Teleton root at ${TELETON_ROOT}`);
350
- }
351
- if (!existsSync2(WORKSPACE_ROOT)) {
352
- mkdirSync2(WORKSPACE_ROOT, { recursive: true });
353
- if (!silent) log2.info(`Created workspace at ${WORKSPACE_ROOT}`);
354
- }
355
- const directories = [
356
- WORKSPACE_PATHS.MEMORY_DIR,
357
- WORKSPACE_PATHS.DOWNLOADS_DIR,
358
- WORKSPACE_PATHS.UPLOADS_DIR,
359
- WORKSPACE_PATHS.TEMP_DIR,
360
- WORKSPACE_PATHS.MEMES_DIR
361
- ];
362
- for (const dir of directories) {
363
- if (!existsSync2(dir)) {
364
- mkdirSync2(dir, { recursive: true });
365
- }
366
- }
367
- const workspace = {
368
- root: TELETON_ROOT,
369
- workspace: WORKSPACE_ROOT,
370
- // Workspace files
371
- soulPath: WORKSPACE_PATHS.SOUL,
372
- memoryPath: WORKSPACE_PATHS.MEMORY,
373
- identityPath: WORKSPACE_PATHS.IDENTITY,
374
- userPath: WORKSPACE_PATHS.USER,
375
- strategyPath: WORKSPACE_PATHS.STRATEGY,
376
- securityPath: WORKSPACE_PATHS.SECURITY,
377
- // Workspace directories
378
- memoryDir: WORKSPACE_PATHS.MEMORY_DIR,
379
- downloadsDir: WORKSPACE_PATHS.DOWNLOADS_DIR,
380
- uploadsDir: WORKSPACE_PATHS.UPLOADS_DIR,
381
- tempDir: WORKSPACE_PATHS.TEMP_DIR,
382
- memesDir: WORKSPACE_PATHS.MEMES_DIR,
383
- // Protected files (outside workspace)
384
- sessionPath: join2(TELETON_ROOT, "telegram_session.txt"),
385
- configPath: join2(TELETON_ROOT, "config.yaml"),
386
- walletPath: join2(TELETON_ROOT, "wallet.json")
387
- };
388
- if (config?.ensureTemplates) {
389
- await bootstrapTemplates(workspace, silent);
390
- }
391
- return workspace;
392
- }
393
- async function bootstrapTemplates(workspace, silent = false) {
394
- const templates = [
395
- { name: "SOUL.md", path: workspace.soulPath },
396
- { name: "MEMORY.md", path: workspace.memoryPath },
397
- { name: "IDENTITY.md", path: workspace.identityPath },
398
- { name: "USER.md", path: workspace.userPath },
399
- { name: "SECURITY.md", path: workspace.securityPath },
400
- { name: "STRATEGY.md", path: workspace.strategyPath }
401
- ];
402
- for (const template of templates) {
403
- if (!existsSync2(template.path)) {
404
- const templateSource = join2(TEMPLATES_DIR, template.name);
405
- if (existsSync2(templateSource)) {
406
- copyFileSync(templateSource, template.path);
407
- if (!silent) log2.info(`Created ${template.name}`);
408
- }
409
- }
410
- }
411
- }
412
- function isNewWorkspace(workspace) {
413
- return !existsSync2(workspace.configPath);
414
- }
415
- function loadTemplate(name) {
416
- const templatePath = join2(TEMPLATES_DIR, name);
417
- if (!existsSync2(templatePath)) {
418
- throw new Error(`Template ${name} not found at ${templatePath}`);
419
- }
420
- return readFileSync2(templatePath, "utf-8");
421
- }
422
-
423
418
  export {
424
419
  DealsConfigSchema,
425
420
  ConfigSchema,
426
421
  expandPath,
427
422
  loadConfig,
428
423
  configExists,
429
- getDefaultConfigPath,
430
- ensureWorkspace,
431
- isNewWorkspace,
432
- loadTemplate
424
+ getDefaultConfigPath
433
425
  };