teleton 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,6 @@
1
- <h1 align="center">Teleton Agent</h1>
1
+ <p align="center">
2
+ <img src="./logo_dark.png" alt="Teleton Agent" width="700" />
3
+ </p>
2
4
 
3
5
  <p align="center"><b>Autonomous AI agent platform for Telegram with native TON blockchain integration</b></p>
4
6
 
@@ -7,21 +9,22 @@
7
9
  <a href="https://nodejs.org/"><img src="https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen" alt="Node.js"></a>
8
10
  <a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-5.7-blue" alt="TypeScript"></a>
9
11
  <a href="https://teletonagent.dev"><img src="https://img.shields.io/badge/Website-teletonagent.dev-ff6600" alt="Website"></a>
10
- <a href="https://deepwiki.com/TONresistor/teleton-agent"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
12
+ <a href="https://docs.teletonagent.dev"><img src="https://img.shields.io/badge/docs-Teleton%20Agents-blue" alt="Documentation"></a>
13
+ <a href="https://ton.org"><img src="https://img.shields.io/badge/Built_on-TON-0098EA?logo=ton&logoColor=white" alt="Built on TON"></a>
11
14
  </p>
12
15
 
13
16
  ---
14
17
 
15
- <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 114 built-in tools, supports 6 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 100+ built-in tools, supports 10 LLM providers, and exposes a Plugin SDK so you can build your own tools on top of the platform.</p>
16
19
 
17
20
  ### Key Highlights
18
21
 
19
22
  - **Full Telegram access** - Operates as a real user via MTProto (GramJS), not a limited bot
20
23
  - **Agentic loop** - Up to 5 iterations of tool calling per message, the agent thinks, acts, observes, and repeats
21
- - **Multi-Provider LLM** - Anthropic, OpenAI, Google Gemini, xAI Grok, Groq, OpenRouter
24
+ - **Multi-Provider LLM** - Anthropic, OpenAI, Google Gemini, xAI Grok, Groq, OpenRouter, Moonshot, Mistral, Cocoon, Local
22
25
  - **TON Blockchain** - Built-in W5R1 wallet, send/receive TON & jettons, swap on STON.fi and DeDust, NFTs, DNS domains
23
26
  - **Persistent memory** - Hybrid RAG (sqlite-vec + FTS5), auto-compaction with AI summarization, daily logs
24
- - **114 built-in tools** - Messaging, media, blockchain, DEX trading, deals, DNS, journaling, and more
27
+ - **100+ built-in tools** - Messaging, media, blockchain, DEX trading, deals, DNS, journaling, and more
25
28
  - **Plugin SDK** - Extend the agent with custom tools, frozen SDK with isolated databases, secrets management, lifecycle hooks
26
29
  - **MCP Client** - Connect external tool servers (stdio/SSE) with 2 lines of YAML, no code, no rebuild
27
30
  - **Secure by design** - Prompt injection defense, sandboxed workspace, plugin isolation, wallet encryption
@@ -48,7 +51,7 @@
48
51
 
49
52
  | Capability | Description |
50
53
  | ----------------------- | --------------------------------------------------------------------------------------------------------------------------- |
51
- | **Multi-Provider LLM** | Switch between Anthropic, OpenAI, Google, xAI, Groq, OpenRouter with one config change |
54
+ | **Multi-Provider LLM** | Switch between Anthropic, OpenAI, Google, xAI, Groq, OpenRouter, Moonshot, Mistral, Cocoon, or Local with one config change |
52
55
  | **RAG + Hybrid Search** | Local ONNX embeddings (384d) or Voyage AI (512d/1024d) with FTS5 keyword + sqlite-vec cosine similarity, fused via RRF |
53
56
  | **Auto-Compaction** | AI-summarized context management prevents overflow, preserves key information in `memory/*.md` files |
54
57
  | **Observation Masking** | Compresses old tool results to one-line summaries, saving ~90% context window |
@@ -405,7 +408,7 @@ src/
405
408
  ├── agent/ # Core agent runtime
406
409
  │ ├── runtime.ts # Agentic loop (5 iterations, tool calling, masking, compaction)
407
410
  │ ├── client.ts # Multi-provider LLM client
408
- │ └── tools/ # 114 built-in tools
411
+ │ └── tools/ # 100+ built-in tools
409
412
  │ ├── register-all.ts # Central tool registration (8 categories, 109 tools)
410
413
  │ ├── registry.ts # Tool registry, scope filtering, provider limits
411
414
  │ ├── module-loader.ts # Built-in module loading (deals → +5 tools)
@@ -460,7 +463,7 @@ src/
460
463
  │ └── loader.ts # 10 sections: soul + security + strategy + memory + context + ...
461
464
  ├── config/ # Configuration
462
465
  │ ├── schema.ts # Zod schemas + validation
463
- │ └── providers.ts # Multi-provider LLM registry (6 providers)
466
+ │ └── providers.ts # Multi-provider LLM registry (10 providers)
464
467
  ├── webui/ # Optional web dashboard
465
468
  │ ├── server.ts # Hono server, auth middleware, static serving
466
469
  │ └── routes/ # 11 API route groups (status, tools, logs, memory, soul, plugins, mcp, tasks, workspace, config, marketplace)
@@ -48,7 +48,6 @@ import {
48
48
  createLogger
49
49
  } from "./chunk-RCMD3U65.js";
50
50
  import {
51
- __require,
52
51
  __toESM
53
52
  } from "./chunk-QGM4M3NI.js";
54
53
 
@@ -660,54 +659,71 @@ var SDK_VERSION = "1.0.0";
660
659
  // src/ton/transfer.ts
661
660
  import { WalletContractV5R1, TonClient, toNano, internal } from "@ton/ton";
662
661
  import { Address, SendMode } from "@ton/core";
662
+
663
+ // src/ton/tx-lock.ts
664
+ var pending = Promise.resolve();
665
+ function withTxLock(fn) {
666
+ const execute = pending.then(fn, fn);
667
+ pending = execute.then(
668
+ () => {
669
+ },
670
+ () => {
671
+ }
672
+ );
673
+ return execute;
674
+ }
675
+
676
+ // src/ton/transfer.ts
663
677
  var log4 = createLogger("TON");
664
678
  async function sendTon(params) {
665
- try {
666
- const { toAddress, amount, comment = "", bounce = false } = params;
667
- if (!Number.isFinite(amount) || amount <= 0) {
668
- log4.error({ amount }, "Invalid transfer amount");
669
- return null;
670
- }
671
- let recipientAddress;
679
+ return withTxLock(async () => {
672
680
  try {
673
- recipientAddress = Address.parse(toAddress);
674
- } catch (e) {
675
- log4.error({ err: e }, `Invalid recipient address: ${toAddress}`);
676
- return null;
677
- }
678
- const keyPair = await getKeyPair();
679
- if (!keyPair) {
680
- log4.error("Wallet not initialized");
681
+ const { toAddress, amount, comment = "", bounce = false } = params;
682
+ if (!Number.isFinite(amount) || amount <= 0) {
683
+ log4.error({ amount }, "Invalid transfer amount");
684
+ return null;
685
+ }
686
+ let recipientAddress;
687
+ try {
688
+ recipientAddress = Address.parse(toAddress);
689
+ } catch (e) {
690
+ log4.error({ err: e }, `Invalid recipient address: ${toAddress}`);
691
+ return null;
692
+ }
693
+ const keyPair = await getKeyPair();
694
+ if (!keyPair) {
695
+ log4.error("Wallet not initialized");
696
+ return null;
697
+ }
698
+ const wallet = WalletContractV5R1.create({
699
+ workchain: 0,
700
+ publicKey: keyPair.publicKey
701
+ });
702
+ const endpoint = await getCachedHttpEndpoint();
703
+ const client = new TonClient({ endpoint });
704
+ const contract = client.open(wallet);
705
+ const seqno = await contract.getSeqno();
706
+ await contract.sendTransfer({
707
+ seqno,
708
+ secretKey: keyPair.secretKey,
709
+ sendMode: SendMode.PAY_GAS_SEPARATELY,
710
+ messages: [
711
+ internal({
712
+ to: recipientAddress,
713
+ value: toNano(amount),
714
+ body: comment,
715
+ bounce
716
+ })
717
+ ]
718
+ });
719
+ const pseudoHash = `${seqno}_${Date.now()}_${amount.toFixed(2)}`;
720
+ log4.info(`Sent ${amount} TON to ${toAddress.slice(0, 8)}... - seqno: ${seqno}`);
721
+ return pseudoHash;
722
+ } catch (error) {
723
+ log4.error({ err: error }, "Error sending TON");
681
724
  return null;
682
725
  }
683
- const wallet = WalletContractV5R1.create({
684
- workchain: 0,
685
- publicKey: keyPair.publicKey
686
- });
687
- const endpoint = await getCachedHttpEndpoint();
688
- const client = new TonClient({ endpoint });
689
- const contract = client.open(wallet);
690
- const seqno = await contract.getSeqno();
691
- await contract.sendTransfer({
692
- seqno,
693
- secretKey: keyPair.secretKey,
694
- sendMode: SendMode.PAY_GAS_SEPARATELY,
695
- messages: [
696
- internal({
697
- to: recipientAddress,
698
- value: toNano(amount),
699
- body: comment,
700
- bounce
701
- })
702
- ]
703
- });
704
- const pseudoHash = `${seqno}_${Date.now()}_${amount.toFixed(2)}`;
705
- log4.info(`Sent ${amount} TON to ${toAddress.slice(0, 8)}... - seqno: ${seqno}`);
706
- return pseudoHash;
707
- } catch (error) {
708
- log4.error({ err: error }, "Error sending TON");
709
- return null;
710
- }
726
+ });
711
727
  }
712
728
 
713
729
  // src/utils/retry.ts
@@ -759,6 +775,8 @@ async function withBlockchainRetry(fn, operation = "blockchain operation") {
759
775
  }
760
776
 
761
777
  // src/sdk/ton.ts
778
+ import { toNano as tonToNano, fromNano as tonFromNano } from "@ton/ton";
779
+ import { Address as TonAddress } from "@ton/core";
762
780
  var DEFAULT_MAX_AGE_MINUTES = 10;
763
781
  var DEFAULT_TX_RETENTION_DAYS = 30;
764
782
  var CLEANUP_PROBABILITY = 0.1;
@@ -927,7 +945,7 @@ function createTonSDK(log7, db) {
927
945
  for (const item of data.balances || []) {
928
946
  const { balance, wallet_address, jetton } = item;
929
947
  if (jetton.verification === "blacklist") continue;
930
- const decimals = jetton.decimals || 9;
948
+ const decimals = jetton.decimals ?? 9;
931
949
  const rawBalance = BigInt(balance);
932
950
  const divisor = BigInt(10 ** decimals);
933
951
  const wholePart = rawBalance / divisor;
@@ -994,68 +1012,79 @@ function createTonSDK(log7, db) {
994
1012
  } catch {
995
1013
  throw new PluginSDKError("Invalid recipient address", "INVALID_ADDRESS");
996
1014
  }
997
- const jettonsResponse = await tonapiFetch(`/accounts/${walletData.address}/jettons`);
998
- if (!jettonsResponse.ok) {
999
- throw new PluginSDKError(
1000
- `Failed to fetch jetton balances: ${jettonsResponse.status}`,
1001
- "OPERATION_FAILED"
1002
- );
1003
- }
1004
- const jettonsData = await jettonsResponse.json();
1005
- const jettonBalance = jettonsData.balances?.find(
1006
- (b) => b.jetton.address.toLowerCase() === jettonAddress.toLowerCase() || Address2.parse(b.jetton.address).toString() === Address2.parse(jettonAddress).toString()
1007
- );
1008
- if (!jettonBalance) {
1009
- throw new PluginSDKError(
1010
- `You don't own any of this jetton: ${jettonAddress}`,
1011
- "OPERATION_FAILED"
1015
+ try {
1016
+ const jettonsResponse = await tonapiFetch(`/accounts/${walletData.address}/jettons`);
1017
+ if (!jettonsResponse.ok) {
1018
+ throw new PluginSDKError(
1019
+ `Failed to fetch jetton balances: ${jettonsResponse.status}`,
1020
+ "OPERATION_FAILED"
1021
+ );
1022
+ }
1023
+ const jettonsData = await jettonsResponse.json();
1024
+ const jettonBalance = jettonsData.balances?.find(
1025
+ (b) => b.jetton.address.toLowerCase() === jettonAddress.toLowerCase() || Address2.parse(b.jetton.address).toString() === Address2.parse(jettonAddress).toString()
1012
1026
  );
1013
- }
1014
- const senderJettonWallet = jettonBalance.wallet_address.address;
1015
- const decimals = jettonBalance.jetton.decimals || 9;
1016
- const currentBalance = BigInt(jettonBalance.balance);
1017
- const amountStr = amount.toFixed(decimals);
1018
- const [whole, frac = ""] = amountStr.split(".");
1019
- const amountInUnits = BigInt(whole + (frac + "0".repeat(decimals)).slice(0, decimals));
1020
- if (amountInUnits > currentBalance) {
1027
+ if (!jettonBalance) {
1028
+ throw new PluginSDKError(
1029
+ `You don't own any of this jetton: ${jettonAddress}`,
1030
+ "OPERATION_FAILED"
1031
+ );
1032
+ }
1033
+ const senderJettonWallet = jettonBalance.wallet_address.address;
1034
+ const decimals = jettonBalance.jetton.decimals ?? 9;
1035
+ const currentBalance = BigInt(jettonBalance.balance);
1036
+ const amountStr = amount.toFixed(decimals);
1037
+ const [whole, frac = ""] = amountStr.split(".");
1038
+ const amountInUnits = BigInt(whole + (frac + "0".repeat(decimals)).slice(0, decimals));
1039
+ if (amountInUnits > currentBalance) {
1040
+ throw new PluginSDKError(
1041
+ `Insufficient balance. Have ${Number(currentBalance) / 10 ** decimals}, need ${amount}`,
1042
+ "OPERATION_FAILED"
1043
+ );
1044
+ }
1045
+ const comment = opts?.comment;
1046
+ let forwardPayload = beginCell().endCell();
1047
+ if (comment) {
1048
+ forwardPayload = beginCell().storeUint(0, 32).storeStringTail(comment).endCell();
1049
+ }
1050
+ const JETTON_TRANSFER_OP = 260734629;
1051
+ const messageBody = beginCell().storeUint(JETTON_TRANSFER_OP, 32).storeUint(0, 64).storeCoins(amountInUnits).storeAddress(Address2.parse(to)).storeAddress(Address2.parse(walletData.address)).storeBit(false).storeCoins(comment ? toNano2("0.01") : BigInt(1)).storeBit(comment ? true : false).storeMaybeRef(comment ? forwardPayload : null).endCell();
1052
+ const keyPair = await getKeyPair();
1053
+ if (!keyPair) {
1054
+ throw new PluginSDKError("Wallet key derivation failed", "OPERATION_FAILED");
1055
+ }
1056
+ const seqno = await withTxLock(async () => {
1057
+ const wallet = WalletContractV5R12.create({
1058
+ workchain: 0,
1059
+ publicKey: keyPair.publicKey
1060
+ });
1061
+ const endpoint = await getCachedHttpEndpoint2();
1062
+ const client = new TonClient2({ endpoint });
1063
+ const walletContract = client.open(wallet);
1064
+ const seq = await walletContract.getSeqno();
1065
+ await walletContract.sendTransfer({
1066
+ seqno: seq,
1067
+ secretKey: keyPair.secretKey,
1068
+ sendMode: SendMode2.PAY_GAS_SEPARATELY,
1069
+ messages: [
1070
+ internal2({
1071
+ to: Address2.parse(senderJettonWallet),
1072
+ value: toNano2("0.05"),
1073
+ body: messageBody,
1074
+ bounce: true
1075
+ })
1076
+ ]
1077
+ });
1078
+ return seq;
1079
+ });
1080
+ return { success: true, seqno };
1081
+ } catch (err) {
1082
+ if (err instanceof PluginSDKError) throw err;
1021
1083
  throw new PluginSDKError(
1022
- `Insufficient balance. Have ${Number(currentBalance) / 10 ** decimals}, need ${amount}`,
1084
+ `Failed to send jetton: ${err instanceof Error ? err.message : String(err)}`,
1023
1085
  "OPERATION_FAILED"
1024
1086
  );
1025
1087
  }
1026
- const comment = opts?.comment;
1027
- let forwardPayload = beginCell().endCell();
1028
- if (comment) {
1029
- forwardPayload = beginCell().storeUint(0, 32).storeStringTail(comment).endCell();
1030
- }
1031
- const JETTON_TRANSFER_OP = 260734629;
1032
- const messageBody = beginCell().storeUint(JETTON_TRANSFER_OP, 32).storeUint(0, 64).storeCoins(amountInUnits).storeAddress(Address2.parse(to)).storeAddress(Address2.parse(walletData.address)).storeBit(false).storeCoins(comment ? toNano2("0.01") : BigInt(1)).storeBit(comment ? true : false).storeMaybeRef(comment ? forwardPayload : null).endCell();
1033
- const keyPair = await getKeyPair();
1034
- if (!keyPair) {
1035
- throw new PluginSDKError("Wallet key derivation failed", "OPERATION_FAILED");
1036
- }
1037
- const wallet = WalletContractV5R12.create({
1038
- workchain: 0,
1039
- publicKey: keyPair.publicKey
1040
- });
1041
- const endpoint = await getCachedHttpEndpoint2();
1042
- const client = new TonClient2({ endpoint });
1043
- const walletContract = client.open(wallet);
1044
- const seqno = await walletContract.getSeqno();
1045
- await walletContract.sendTransfer({
1046
- seqno,
1047
- secretKey: keyPair.secretKey,
1048
- sendMode: SendMode2.PAY_GAS_SEPARATELY + SendMode2.IGNORE_ERRORS,
1049
- messages: [
1050
- internal2({
1051
- to: Address2.parse(senderJettonWallet),
1052
- value: toNano2("0.05"),
1053
- body: messageBody,
1054
- bounce: true
1055
- })
1056
- ]
1057
- });
1058
- return { success: true, seqno };
1059
1088
  },
1060
1089
  async getJettonWalletAddress(ownerAddress, jettonAddress) {
1061
1090
  try {
@@ -1113,8 +1142,7 @@ function createTonSDK(log7, db) {
1113
1142
  // ─── Utilities ───────────────────────────────────────────────
1114
1143
  toNano(amount) {
1115
1144
  try {
1116
- const { toNano: convert } = __require("@ton/ton");
1117
- return convert(String(amount));
1145
+ return tonToNano(String(amount));
1118
1146
  } catch (err) {
1119
1147
  throw new PluginSDKError(
1120
1148
  `toNano conversion failed: ${err instanceof Error ? err.message : String(err)}`,
@@ -1123,13 +1151,11 @@ function createTonSDK(log7, db) {
1123
1151
  }
1124
1152
  },
1125
1153
  fromNano(nano) {
1126
- const { fromNano: convert } = __require("@ton/ton");
1127
- return convert(nano);
1154
+ return tonFromNano(nano);
1128
1155
  },
1129
1156
  validateAddress(address) {
1130
1157
  try {
1131
- const { Address: Address2 } = __require("@ton/core");
1132
- Address2.parse(address);
1158
+ TonAddress.parse(address);
1133
1159
  return true;
1134
1160
  } catch {
1135
1161
  return false;