From 46b3b54e80254179ae69b73bbe3f120e866db31e Mon Sep 17 00:00:00 2001 From: TONresistor Date: Fri, 22 May 2026 02:54:26 +0200 Subject: [PATCH 001/151] refactor(tools): mandatory ternary tool mode (user/bot/both) Replace the optional requiredMode flag with a required ToolMode field on ToolEntry, so the compiler rejects any tool that does not declare which Telegram mode(s) it runs in. The registry filters on the three-way mode in passesFilters/execute/setMode. Honest gap handling: getClient() and the bot bridge's getMessages() now throw a clear error in bot mode instead of a cryptic TypeError or a silently empty result. Move bot_inline_send out of the misnamed tools/bot/ directory into telegram/messaging/ and drop the now-empty folder. --- src/agent/tools/bot/index.ts | 16 ------ src/agent/tools/dedust/index.ts | 16 ++++-- src/agent/tools/dns/index.ts | 39 +++++++++++--- src/agent/tools/journal/index.ts | 18 +++++-- src/agent/tools/module-loader.ts | 4 +- src/agent/tools/register-all.ts | 8 ++- src/agent/tools/registry.ts | 28 +++++----- src/agent/tools/stonfi/index.ts | 16 ++++-- src/agent/tools/telegram/chats/index.ts | 23 ++++---- src/agent/tools/telegram/contacts/index.ts | 10 ++-- src/agent/tools/telegram/folders/index.ts | 6 +-- .../telegram/gifts/get-available-gifts-bot.ts | 2 +- .../tools/telegram/gifts/get-user-gifts.ts | 2 +- src/agent/tools/telegram/gifts/index.ts | 26 +++++----- src/agent/tools/telegram/groups/index.ts | 13 ++--- src/agent/tools/telegram/interactive/index.ts | 8 +-- src/agent/tools/telegram/media/index.ts | 13 ++--- src/agent/tools/telegram/memory/index.ts | 26 ++++++++-- .../messaging}/__tests__/inline-send.test.ts | 2 +- src/agent/tools/telegram/messaging/index.ts | 30 ++++++++--- .../messaging}/inline-send.ts | 10 ++-- src/agent/tools/telegram/profile/index.ts | 8 +-- src/agent/tools/telegram/send-buttons.ts | 2 +- src/agent/tools/telegram/stars/index.ts | 4 +- src/agent/tools/telegram/stickers/index.ts | 8 +-- src/agent/tools/telegram/stories/index.ts | 2 +- src/agent/tools/telegram/tasks/index.ts | 2 +- src/agent/tools/ton/index.ts | 52 +++++++++++++------ src/agent/tools/types.ts | 16 +++++- src/agent/tools/web/index.ts | 4 +- src/agent/tools/workspace/index.ts | 9 ++-- src/deals/module.ts | 16 +++++- src/sdk/telegram-utils.ts | 5 ++ src/sdk/telegram.ts | 1 + src/telegram/bridges/bot.ts | 4 +- 35 files changed, 288 insertions(+), 161 deletions(-) delete mode 100644 src/agent/tools/bot/index.ts rename src/agent/tools/{bot => telegram/messaging}/__tests__/inline-send.test.ts (98%) rename src/agent/tools/{bot => telegram/messaging}/inline-send.ts (91%) diff --git a/src/agent/tools/bot/index.ts b/src/agent/tools/bot/index.ts deleted file mode 100644 index 33fd56d0..00000000 --- a/src/agent/tools/bot/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Bot tools — inline mode integration for plugins. - */ - -import type { ToolEntry } from "../types.js"; -import { botInlineSendTool, botInlineSendExecutor } from "./inline-send.js"; - -export const tools: ToolEntry[] = [ - { - tool: botInlineSendTool, - executor: botInlineSendExecutor, - scope: "always", - requiredMode: "user", - tags: ["bot"], - }, -]; diff --git a/src/agent/tools/dedust/index.ts b/src/agent/tools/dedust/index.ts index 37cfeb0e..a2dd88a4 100644 --- a/src/agent/tools/dedust/index.ts +++ b/src/agent/tools/dedust/index.ts @@ -12,9 +12,15 @@ export { dedustPricesTool, dedustPricesExecutor }; export { dedustTokenInfoTool, dedustTokenInfoExecutor }; export const tools: ToolEntry[] = [ - { tool: dedustSwapTool, executor: dedustSwapExecutor, scope: "dm-only", tags: ["finance"] }, - { tool: dedustQuoteTool, executor: dedustQuoteExecutor, tags: ["finance"] }, - { tool: dedustPoolsTool, executor: dedustPoolsExecutor, tags: ["finance"] }, - { tool: dedustPricesTool, executor: dedustPricesExecutor, tags: ["finance"] }, - { tool: dedustTokenInfoTool, executor: dedustTokenInfoExecutor, tags: ["finance"] }, + { + tool: dedustSwapTool, + executor: dedustSwapExecutor, + scope: "dm-only", + mode: "both", + tags: ["finance"], + }, + { tool: dedustQuoteTool, executor: dedustQuoteExecutor, mode: "both", tags: ["finance"] }, + { tool: dedustPoolsTool, executor: dedustPoolsExecutor, mode: "both", tags: ["finance"] }, + { tool: dedustPricesTool, executor: dedustPricesExecutor, mode: "both", tags: ["finance"] }, + { tool: dedustTokenInfoTool, executor: dedustTokenInfoExecutor, mode: "both", tags: ["finance"] }, ]; diff --git a/src/agent/tools/dns/index.ts b/src/agent/tools/dns/index.ts index 5bd92c1d..f2a8b176 100644 --- a/src/agent/tools/dns/index.ts +++ b/src/agent/tools/dns/index.ts @@ -22,13 +22,38 @@ export const tools: ToolEntry[] = [ tool: dnsStartAuctionTool, executor: dnsStartAuctionExecutor, scope: "dm-only", + mode: "both", tags: ["automation"], }, - { tool: dnsBidTool, executor: dnsBidExecutor, scope: "dm-only", tags: ["automation"] }, - { tool: dnsLinkTool, executor: dnsLinkExecutor, scope: "dm-only", tags: ["automation"] }, - { tool: dnsUnlinkTool, executor: dnsUnlinkExecutor, scope: "dm-only", tags: ["automation"] }, - { tool: dnsSetSiteTool, executor: dnsSetSiteExecutor, scope: "dm-only", tags: ["automation"] }, - { tool: dnsCheckTool, executor: dnsCheckExecutor, tags: ["automation"] }, - { tool: dnsAuctionsTool, executor: dnsAuctionsExecutor, tags: ["automation"] }, - { tool: dnsResolveTool, executor: dnsResolveExecutor, tags: ["automation"] }, + { + tool: dnsBidTool, + executor: dnsBidExecutor, + scope: "dm-only", + mode: "both", + tags: ["automation"], + }, + { + tool: dnsLinkTool, + executor: dnsLinkExecutor, + scope: "dm-only", + mode: "both", + tags: ["automation"], + }, + { + tool: dnsUnlinkTool, + executor: dnsUnlinkExecutor, + scope: "dm-only", + mode: "both", + tags: ["automation"], + }, + { + tool: dnsSetSiteTool, + executor: dnsSetSiteExecutor, + scope: "dm-only", + mode: "both", + tags: ["automation"], + }, + { tool: dnsCheckTool, executor: dnsCheckExecutor, mode: "both", tags: ["automation"] }, + { tool: dnsAuctionsTool, executor: dnsAuctionsExecutor, mode: "both", tags: ["automation"] }, + { tool: dnsResolveTool, executor: dnsResolveExecutor, mode: "both", tags: ["automation"] }, ]; diff --git a/src/agent/tools/journal/index.ts b/src/agent/tools/journal/index.ts index b02d6f65..e7b92cc0 100644 --- a/src/agent/tools/journal/index.ts +++ b/src/agent/tools/journal/index.ts @@ -18,9 +18,21 @@ export { journalQueryTool, journalQueryExecutor }; export { journalUpdateTool, journalUpdateExecutor }; export const tools: ToolEntry[] = [ - { tool: journalLogTool, executor: journalLogExecutor, scope: "dm-only", tags: ["finance"] }, - { tool: journalUpdateTool, executor: journalUpdateExecutor, scope: "dm-only", tags: ["finance"] }, - { tool: journalQueryTool, executor: journalQueryExecutor, tags: ["finance"] }, + { + tool: journalLogTool, + executor: journalLogExecutor, + scope: "dm-only", + mode: "both", + tags: ["finance"], + }, + { + tool: journalUpdateTool, + executor: journalUpdateExecutor, + scope: "dm-only", + mode: "both", + tags: ["finance"], + }, + { tool: journalQueryTool, executor: journalQueryExecutor, mode: "both", tags: ["finance"] }, ]; // Re-export types from journal-store diff --git a/src/agent/tools/module-loader.ts b/src/agent/tools/module-loader.ts index ba91e7ef..68e5c20d 100644 --- a/src/agent/tools/module-loader.ts +++ b/src/agent/tools/module-loader.ts @@ -31,8 +31,8 @@ export function loadModules( mod.migrate?.(db); const tools = mod.tools(config); - for (const { tool, executor, scope } of tools) { - registry.register(tool, executor, scope); + for (const { tool, executor, scope, mode } of tools) { + registry.register(tool, executor, scope, mode); } loaded.push(mod); diff --git a/src/agent/tools/register-all.ts b/src/agent/tools/register-all.ts index ca625d03..5a2e6c72 100644 --- a/src/agent/tools/register-all.ts +++ b/src/agent/tools/register-all.ts @@ -16,7 +16,6 @@ import { tools as dedustTools } from "./dedust/index.js"; import { tools as journalTools } from "./journal/index.js"; import { tools as workspaceTools } from "./workspace/index.js"; import { tools as webTools } from "./web/index.js"; -import { tools as botTools } from "./bot/index.js"; import { toolSearchTool, createToolSearchExecutor } from "./search/index.js"; const ALL_CATEGORIES: ToolEntry[][] = [ @@ -28,13 +27,12 @@ const ALL_CATEGORIES: ToolEntry[][] = [ journalTools, workspaceTools, webTools, - botTools, ]; export function registerAllTools(registry: ToolRegistry): void { for (const category of ALL_CATEGORIES) { - for (const { tool, executor, scope, requiredMode, tags } of category) { - registry.register(tool, executor, scope, requiredMode, tags); + for (const { tool, executor, scope, mode, tags } of category) { + registry.register(tool, executor, scope, mode, tags); } } @@ -43,5 +41,5 @@ export function registerAllTools(registry: ToolRegistry): void { // The executor lazily reads registry.getToolIndex() + registry.getEmbedder() at call time, // both of which are set during startAgent() — after this registration. const toolSearchExecutor = createToolSearchExecutor(registry); - registry.register(toolSearchTool, toolSearchExecutor, "open", undefined, ["core"]); + registry.register(toolSearchTool, toolSearchExecutor, "open", "both", ["core"]); } diff --git a/src/agent/tools/registry.ts b/src/agent/tools/registry.ts index dae48b52..4b2596c1 100644 --- a/src/agent/tools/registry.ts +++ b/src/agent/tools/registry.ts @@ -7,6 +7,7 @@ import type { ToolContext, ToolEntry, ToolExecutor, + ToolMode, ToolResult, ToolScope, } from "./types.js"; @@ -39,7 +40,7 @@ export class ToolRegistry { private embedderRef: EmbeddingProvider | null = null; private onToolsChangedCallbacks: Array<(removed: string[], added: PiAiTool[]) => void> = []; private mode: "user" | "bot"; - private requiredModes: Map = new Map(); + private toolModes: Map = new Map(); private toolTags: Map = new Map(); private activeToolset: string | null = null; // null = "full" (no filtering) private allowFrom: Set = new Set(); @@ -59,7 +60,7 @@ export class ToolRegistry { tool: Tool, executor: ToolExecutor, scope?: ToolScope, - requiredMode?: "user" | "bot", + mode: ToolMode = "both", tags?: string[] ): void { if (this.tools.has(tool.name)) { @@ -69,9 +70,7 @@ export class ToolRegistry { if (scope && scope !== "always" && scope !== "open") { this.scopes.set(tool.name, scope); } - if (requiredMode) { - this.requiredModes.set(tool.name, requiredMode); - } + this.toolModes.set(tool.name, mode); if (tags && tags.length > 0) { this.toolTags.set(tool.name, tags); } @@ -87,8 +86,8 @@ export class ToolRegistry { this.mode = mode; this.toolArrayCache = null; const count = Array.from(this.tools.values()).filter((rt) => { - const reqMode = this.requiredModes.get(rt.tool.name); - return !reqMode || reqMode === mode; + const toolMode = this.toolModes.get(rt.tool.name); + return !toolMode || toolMode === "both" || toolMode === mode; }).length; log.info(`Mode switched to ${mode}, ${count} tools available`); } @@ -157,11 +156,11 @@ export class ToolRegistry { } // Check mode restriction (defense-in-depth: tools are also filtered from LLM tool list) - const reqMode = this.requiredModes.get(toolCall.name); - if (reqMode && reqMode !== this.mode) { + const toolMode = this.toolModes.get(toolCall.name); + if (toolMode && toolMode !== "both" && toolMode !== this.mode) { return { success: false, - error: `Tool "${toolCall.name}" requires ${reqMode} mode (current: ${this.mode})`, + error: `Tool "${toolCall.name}" requires ${toolMode} mode (current: ${this.mode})`, }; } @@ -420,6 +419,7 @@ export class ToolRegistry { if (scope && scope !== "always" && scope !== "open") { this.scopes.set(tool.name, scope); } + this.toolModes.set(tool.name, "both"); this.toolModules.set(tool.name, pluginName); names.push(tool.name); } @@ -475,6 +475,7 @@ export class ToolRegistry { if (scope && scope !== "always" && scope !== "open") { this.scopes.set(tool.name, scope); } + this.toolModes.set(tool.name, "both"); this.toolModules.set(tool.name, pluginName); names.push(tool.name); } @@ -514,6 +515,7 @@ export class ToolRegistry { for (const name of tracked) { this.tools.delete(name); this.scopes.delete(name); + this.toolModes.delete(name); this.toolModules.delete(name); } this.pluginToolNames.delete(pluginName); @@ -561,7 +563,7 @@ export class ToolRegistry { tool: registered.tool, executor: registered.executor, scope: this.getEffectiveScope(name), - requiredMode: this.requiredModes.get(name), + mode: this.toolModes.get(name) ?? "both", tags: this.toolTags.get(name), }; } @@ -580,8 +582,8 @@ export class ToolRegistry { if (!this.tools.has(name)) return false; // Mode restriction (user vs bot) - const reqMode = this.requiredModes.get(name); - if (reqMode && reqMode !== this.mode) return false; + const toolMode = this.toolModes.get(name); + if (toolMode && toolMode !== "both" && toolMode !== this.mode) return false; // Active toolset profile filter if (this.activeToolset) { diff --git a/src/agent/tools/stonfi/index.ts b/src/agent/tools/stonfi/index.ts index 6985e127..4e069775 100644 --- a/src/agent/tools/stonfi/index.ts +++ b/src/agent/tools/stonfi/index.ts @@ -12,9 +12,15 @@ export { stonfiTrendingTool, stonfiTrendingExecutor }; export { stonfiPoolsTool, stonfiPoolsExecutor }; export const tools: ToolEntry[] = [ - { tool: stonfiSwapTool, executor: stonfiSwapExecutor, scope: "dm-only", tags: ["finance"] }, - { tool: stonfiQuoteTool, executor: stonfiQuoteExecutor, tags: ["finance"] }, - { tool: stonfiSearchTool, executor: stonfiSearchExecutor, tags: ["finance"] }, - { tool: stonfiTrendingTool, executor: stonfiTrendingExecutor, tags: ["finance"] }, - { tool: stonfiPoolsTool, executor: stonfiPoolsExecutor, tags: ["finance"] }, + { + tool: stonfiSwapTool, + executor: stonfiSwapExecutor, + scope: "dm-only", + mode: "both", + tags: ["finance"], + }, + { tool: stonfiQuoteTool, executor: stonfiQuoteExecutor, mode: "both", tags: ["finance"] }, + { tool: stonfiSearchTool, executor: stonfiSearchExecutor, mode: "both", tags: ["finance"] }, + { tool: stonfiTrendingTool, executor: stonfiTrendingExecutor, mode: "both", tags: ["finance"] }, + { tool: stonfiPoolsTool, executor: stonfiPoolsExecutor, mode: "both", tags: ["finance"] }, ]; diff --git a/src/agent/tools/telegram/chats/index.ts b/src/agent/tools/telegram/chats/index.ts index a3a400d4..0703806a 100644 --- a/src/agent/tools/telegram/chats/index.ts +++ b/src/agent/tools/telegram/chats/index.ts @@ -44,80 +44,81 @@ export const tools: ToolEntry[] = [ { tool: telegramGetDialogsTool, executor: telegramGetDialogsExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramGetHistoryTool, executor: telegramGetHistoryExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramGetChatInfoTool, executor: telegramGetChatInfoExecutor, + mode: "both", tags: ["social"], }, { tool: telegramMarkAsReadTool, executor: telegramMarkAsReadExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramJoinChannelTool, executor: telegramJoinChannelExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramLeaveChannelTool, executor: telegramLeaveChannelExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramCreateChannelTool, executor: telegramCreateChannelExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramEditChannelInfoTool, executor: telegramEditChannelInfoExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramInviteToChannelTool, executor: telegramInviteToChannelExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramGetAdminedChannelsTool, executor: telegramGetAdminedChannelsExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramCheckChannelUsernameTool, executor: telegramCheckChannelUsernameExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramSetChannelUsernameTool, executor: telegramSetChannelUsernameExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, ]; diff --git a/src/agent/tools/telegram/contacts/index.ts b/src/agent/tools/telegram/contacts/index.ts index 1b1ce34c..0fd2c088 100644 --- a/src/agent/tools/telegram/contacts/index.ts +++ b/src/agent/tools/telegram/contacts/index.ts @@ -16,32 +16,32 @@ export const tools: ToolEntry[] = [ tool: telegramBlockUserTool, executor: telegramBlockUserExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramGetBlockedTool, executor: telegramGetBlockedExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramGetCommonChatsTool, executor: telegramGetCommonChatsExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramGetUserInfoTool, executor: telegramGetUserInfoExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramCheckUsernameTool, executor: telegramCheckUsernameExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, ]; diff --git a/src/agent/tools/telegram/folders/index.ts b/src/agent/tools/telegram/folders/index.ts index a87b7d2f..0b1ca145 100644 --- a/src/agent/tools/telegram/folders/index.ts +++ b/src/agent/tools/telegram/folders/index.ts @@ -14,19 +14,19 @@ export const tools: ToolEntry[] = [ { tool: telegramGetFoldersTool, executor: telegramGetFoldersExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramCreateFolderTool, executor: telegramCreateFolderExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramAddChatToFolderTool, executor: telegramAddChatToFolderExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, ]; diff --git a/src/agent/tools/telegram/gifts/get-available-gifts-bot.ts b/src/agent/tools/telegram/gifts/get-available-gifts-bot.ts index 9c1f95c0..24fbf7d1 100644 --- a/src/agent/tools/telegram/gifts/get-available-gifts-bot.ts +++ b/src/agent/tools/telegram/gifts/get-available-gifts-bot.ts @@ -59,6 +59,6 @@ const executor = async (_params: any, context: any) => { export const getAvailableGiftsBotEntry: ToolEntry = { tool, executor, - requiredMode: "bot", + mode: "bot", tags: ["finance"], }; diff --git a/src/agent/tools/telegram/gifts/get-user-gifts.ts b/src/agent/tools/telegram/gifts/get-user-gifts.ts index 8958da8e..fc675682 100644 --- a/src/agent/tools/telegram/gifts/get-user-gifts.ts +++ b/src/agent/tools/telegram/gifts/get-user-gifts.ts @@ -66,6 +66,6 @@ const executor = async (params: any, context: any) => { export const getUserGiftsEntry: ToolEntry = { tool, executor, - requiredMode: "bot", + mode: "bot", tags: ["finance"], }; diff --git a/src/agent/tools/telegram/gifts/index.ts b/src/agent/tools/telegram/gifts/index.ts index b981479b..ec95017c 100644 --- a/src/agent/tools/telegram/gifts/index.ts +++ b/src/agent/tools/telegram/gifts/index.ts @@ -51,86 +51,86 @@ export const tools: ToolEntry[] = [ { tool: telegramGetAvailableGiftsTool, executor: telegramGetAvailableGiftsExecutor, - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramSendGiftTool, executor: telegramSendGiftExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramGetMyGiftsTool, executor: telegramGetMyGiftsExecutor, - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramTransferCollectibleTool, executor: telegramTransferCollectibleExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramSetCollectiblePriceTool, executor: telegramSetCollectiblePriceExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramGetResaleGiftsTool, executor: telegramGetResaleGiftsExecutor, - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramBuyResaleGiftTool, executor: telegramBuyResaleGiftExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramSetGiftStatusTool, executor: telegramSetGiftStatusExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramGetCollectibleInfoTool, executor: telegramGetCollectibleInfoExecutor, - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramGetUniqueGiftTool, executor: telegramGetUniqueGiftExecutor, - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramGetUniqueGiftValueTool, executor: telegramGetUniqueGiftValueExecutor, - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramSendGiftOfferTool, executor: telegramSendGiftOfferExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramResolveGiftOfferTool, executor: telegramResolveGiftOfferExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["finance"], }, getUserGiftsEntry, diff --git a/src/agent/tools/telegram/groups/index.ts b/src/agent/tools/telegram/groups/index.ts index b971fc2f..42b28902 100644 --- a/src/agent/tools/telegram/groups/index.ts +++ b/src/agent/tools/telegram/groups/index.ts @@ -32,47 +32,48 @@ export const tools: ToolEntry[] = [ { tool: telegramGetMeTool, executor: telegramGetMeExecutor, + mode: "both", tags: ["social"], }, { tool: telegramGetParticipantsTool, executor: telegramGetParticipantsExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramKickUserTool, executor: telegramKickUserExecutor, scope: "group-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramBanUserTool, executor: telegramBanUserExecutor, scope: "group-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramUnbanUserTool, executor: telegramUnbanUserExecutor, scope: "group-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramCreateGroupTool, executor: telegramCreateGroupExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramSetChatPhotoTool, executor: telegramSetChatPhotoExecutor, scope: "group-only", - requiredMode: "user", + mode: "user", tags: ["admin"], }, ]; diff --git a/src/agent/tools/telegram/interactive/index.ts b/src/agent/tools/telegram/interactive/index.ts index ff957fbf..947b9e43 100644 --- a/src/agent/tools/telegram/interactive/index.ts +++ b/src/agent/tools/telegram/interactive/index.ts @@ -15,29 +15,31 @@ export const tools: ToolEntry[] = [ { tool: telegramCreatePollTool, executor: telegramCreatePollExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramCreateQuizTool, executor: telegramCreateQuizExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramReplyKeyboardTool, executor: telegramReplyKeyboardExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramReactTool, executor: telegramReactExecutor, + mode: "both", tags: ["core"], }, { tool: telegramSendDiceTool, executor: telegramSendDiceExecutor, + mode: "both", tags: ["media"], }, ]; diff --git a/src/agent/tools/telegram/media/index.ts b/src/agent/tools/telegram/media/index.ts index 03238310..16c85280 100644 --- a/src/agent/tools/telegram/media/index.ts +++ b/src/agent/tools/telegram/media/index.ts @@ -22,42 +22,43 @@ export const tools: ToolEntry[] = [ { tool: telegramSendPhotoTool, executor: telegramSendPhotoExecutor, + mode: "both", tags: ["media"], }, { tool: telegramSendVoiceTool, executor: telegramSendVoiceExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, { tool: telegramSendStickerTool, executor: telegramSendStickerExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, { tool: telegramSendGifTool, executor: telegramSendGifExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, { tool: telegramDownloadMediaTool, executor: telegramDownloadMediaExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, { tool: visionAnalyzeTool, executor: visionAnalyzeExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, { tool: telegramTranscribeAudioTool, executor: telegramTranscribeAudioExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, ]; diff --git a/src/agent/tools/telegram/memory/index.ts b/src/agent/tools/telegram/memory/index.ts index 23947964..28cb71c4 100644 --- a/src/agent/tools/telegram/memory/index.ts +++ b/src/agent/tools/telegram/memory/index.ts @@ -10,8 +10,26 @@ export { memorySearchTool, memorySearchExecutor }; export { sessionSearchTool, sessionSearchExecutor }; export const tools: ToolEntry[] = [ - { tool: memoryWriteTool, executor: memoryWriteExecutor, scope: "dm-only", tags: ["core"] }, - { tool: memoryReadTool, executor: memoryReadExecutor, tags: ["core"] }, - { tool: memorySearchTool, executor: memorySearchExecutor, scope: "dm-only", tags: ["core"] }, - { tool: sessionSearchTool, executor: sessionSearchExecutor, scope: "dm-only", tags: ["core"] }, + { + tool: memoryWriteTool, + executor: memoryWriteExecutor, + scope: "dm-only", + mode: "both", + tags: ["core"], + }, + { tool: memoryReadTool, executor: memoryReadExecutor, mode: "both", tags: ["core"] }, + { + tool: memorySearchTool, + executor: memorySearchExecutor, + scope: "dm-only", + mode: "both", + tags: ["core"], + }, + { + tool: sessionSearchTool, + executor: sessionSearchExecutor, + scope: "dm-only", + mode: "both", + tags: ["core"], + }, ]; diff --git a/src/agent/tools/bot/__tests__/inline-send.test.ts b/src/agent/tools/telegram/messaging/__tests__/inline-send.test.ts similarity index 98% rename from src/agent/tools/bot/__tests__/inline-send.test.ts rename to src/agent/tools/telegram/messaging/__tests__/inline-send.test.ts index b1a812cf..12fe53ef 100644 --- a/src/agent/tools/bot/__tests__/inline-send.test.ts +++ b/src/agent/tools/telegram/messaging/__tests__/inline-send.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { botInlineSendExecutor } from "../inline-send.js"; // Mock the gramjs-bigint module -vi.mock("../../../../utils/gramjs-bigint.js", () => ({ +vi.mock("../../../../../utils/gramjs-bigint.js", () => ({ randomLong: () => BigInt(12345), })); diff --git a/src/agent/tools/telegram/messaging/index.ts b/src/agent/tools/telegram/messaging/index.ts index 2fff4661..bc523298 100644 --- a/src/agent/tools/telegram/messaging/index.ts +++ b/src/agent/tools/telegram/messaging/index.ts @@ -27,6 +27,7 @@ import { telegramSendScheduledNowTool, telegramSendScheduledNowExecutor, } from "./send-scheduled-now.js"; +import { botInlineSendTool, botInlineSendExecutor } from "./inline-send.js"; import type { ToolEntry } from "../../types.js"; export { telegramSendMessageTool, telegramSendMessageExecutor }; @@ -46,79 +47,92 @@ export { telegramGetRepliesTool, telegramGetRepliesExecutor }; export { telegramGetScheduledMessagesTool, telegramGetScheduledMessagesExecutor }; export { telegramDeleteScheduledMessageTool, telegramDeleteScheduledMessageExecutor }; export { telegramSendScheduledNowTool, telegramSendScheduledNowExecutor }; +export { botInlineSendTool, botInlineSendExecutor }; export const tools: ToolEntry[] = [ { tool: telegramSendMessageTool, executor: telegramSendMessageExecutor, + mode: "both", tags: ["core"], }, { tool: telegramQuoteReplyTool, executor: telegramQuoteReplyExecutor, - requiredMode: "user", + mode: "user", tags: ["core"], }, { tool: telegramGetRepliesTool, executor: telegramGetRepliesExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramEditMessageTool, executor: telegramEditMessageExecutor, + mode: "both", tags: ["core"], }, { tool: telegramScheduleMessageTool, executor: telegramScheduleMessageExecutor, - requiredMode: "user", + mode: "user", tags: ["automation"], }, { tool: telegramGetScheduledMessagesTool, executor: telegramGetScheduledMessagesExecutor, - requiredMode: "user", + mode: "user", tags: ["automation"], }, { tool: telegramDeleteScheduledMessageTool, executor: telegramDeleteScheduledMessageExecutor, - requiredMode: "user", + mode: "user", tags: ["automation"], }, { tool: telegramSendScheduledNowTool, executor: telegramSendScheduledNowExecutor, - requiredMode: "user", + mode: "user", tags: ["automation"], }, { tool: telegramSearchMessagesTool, executor: telegramSearchMessagesExecutor, - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramPinMessageTool, executor: telegramPinMessageExecutor, + mode: "both", tags: ["admin"], }, { tool: telegramUnpinMessageTool, executor: telegramUnpinMessageExecutor, - requiredMode: "user", + mode: "user", tags: ["admin"], }, { tool: telegramForwardMessageTool, executor: telegramForwardMessageExecutor, + mode: "both", tags: ["social"], }, { tool: telegramDeleteMessageTool, executor: telegramDeleteMessageExecutor, + mode: "both", tags: ["core"], }, + { + tool: botInlineSendTool, + executor: botInlineSendExecutor, + scope: "always", + mode: "user", + tags: ["bot"], + }, ]; diff --git a/src/agent/tools/bot/inline-send.ts b/src/agent/tools/telegram/messaging/inline-send.ts similarity index 91% rename from src/agent/tools/bot/inline-send.ts rename to src/agent/tools/telegram/messaging/inline-send.ts index 4063141c..ae792e83 100644 --- a/src/agent/tools/bot/inline-send.ts +++ b/src/agent/tools/telegram/messaging/inline-send.ts @@ -5,11 +5,11 @@ import { Api } from "telegram"; import { Type } from "@sinclair/typebox"; -import { randomLong } from "../../../utils/gramjs-bigint.js"; -import type { Tool, ToolExecutor } from "../types.js"; -import { createLogger } from "../../../utils/logger.js"; -import { getErrorMessage } from "../../../utils/errors.js"; -import { getClient } from "../../../sdk/telegram-utils.js"; +import { randomLong } from "../../../../utils/gramjs-bigint.js"; +import type { Tool, ToolExecutor } from "../../types.js"; +import { createLogger } from "../../../../utils/logger.js"; +import { getErrorMessage } from "../../../../utils/errors.js"; +import { getClient } from "../../../../sdk/telegram-utils.js"; const log = createLogger("BotInlineSend"); diff --git a/src/agent/tools/telegram/profile/index.ts b/src/agent/tools/telegram/profile/index.ts index 8c705a13..15430ba3 100644 --- a/src/agent/tools/telegram/profile/index.ts +++ b/src/agent/tools/telegram/profile/index.ts @@ -17,28 +17,28 @@ export const tools: ToolEntry[] = [ tool: telegramUpdateProfileTool, executor: telegramUpdateProfileExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramSetBioTool, executor: telegramSetBioExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramSetUsernameTool, executor: telegramSetUsernameExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["social"], }, { tool: telegramSetPersonalChannelTool, executor: telegramSetPersonalChannelExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["social"], }, ]; diff --git a/src/agent/tools/telegram/send-buttons.ts b/src/agent/tools/telegram/send-buttons.ts index fc527576..ce070596 100644 --- a/src/agent/tools/telegram/send-buttons.ts +++ b/src/agent/tools/telegram/send-buttons.ts @@ -58,6 +58,6 @@ export const sendButtonsEntry: ToolEntry = { tool, executor, scope: "always", - requiredMode: "bot", + mode: "bot", tags: ["core", "bot"], }; diff --git a/src/agent/tools/telegram/stars/index.ts b/src/agent/tools/telegram/stars/index.ts index 9cf03009..ef2ec331 100644 --- a/src/agent/tools/telegram/stars/index.ts +++ b/src/agent/tools/telegram/stars/index.ts @@ -17,14 +17,14 @@ export const tools: ToolEntry[] = [ tool: telegramGetStarsBalanceTool, executor: telegramGetStarsBalanceExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["finance"], }, { tool: telegramGetStarsTransactionsTool, executor: telegramGetStarsTransactionsExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["finance"], }, ]; diff --git a/src/agent/tools/telegram/stickers/index.ts b/src/agent/tools/telegram/stickers/index.ts index fe503fc0..4bde04d4 100644 --- a/src/agent/tools/telegram/stickers/index.ts +++ b/src/agent/tools/telegram/stickers/index.ts @@ -13,25 +13,25 @@ export const tools: ToolEntry[] = [ { tool: telegramSearchStickersTool, executor: telegramSearchStickersExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, { tool: telegramSearchGifsTool, executor: telegramSearchGifsExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, { tool: telegramGetMyStickersTool, executor: telegramGetMyStickersExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, { tool: telegramAddStickerSetTool, executor: telegramAddStickerSetExecutor, - requiredMode: "user", + mode: "user", tags: ["media"], }, ]; diff --git a/src/agent/tools/telegram/stories/index.ts b/src/agent/tools/telegram/stories/index.ts index 2155f8b6..0a4f78ea 100644 --- a/src/agent/tools/telegram/stories/index.ts +++ b/src/agent/tools/telegram/stories/index.ts @@ -8,7 +8,7 @@ export const tools: ToolEntry[] = [ tool: telegramSendStoryTool, executor: telegramSendStoryExecutor, scope: "dm-only", - requiredMode: "user", + mode: "user", tags: ["social"], }, ]; diff --git a/src/agent/tools/telegram/tasks/index.ts b/src/agent/tools/telegram/tasks/index.ts index 1467bec9..9d84a1f3 100644 --- a/src/agent/tools/telegram/tasks/index.ts +++ b/src/agent/tools/telegram/tasks/index.ts @@ -10,7 +10,7 @@ export const tools: ToolEntry[] = [ { tool: telegramCreateScheduledTaskTool, executor: telegramCreateScheduledTaskExecutor, - requiredMode: "user", + mode: "user", tags: ["automation"], }, ]; diff --git a/src/agent/tools/ton/index.ts b/src/agent/tools/ton/index.ts index 71d5a6bf..439e9afd 100644 --- a/src/agent/tools/ton/index.ts +++ b/src/agent/tools/ton/index.ts @@ -32,19 +32,41 @@ export { jettonHistoryTool, jettonHistoryExecutor }; export { dexQuoteTool, dexQuoteExecutor }; export const tools: ToolEntry[] = [ - { tool: tonSendTool, executor: tonSendExecutor, scope: "dm-only", tags: ["finance"] }, - { tool: tonGetAddressTool, executor: tonGetAddressExecutor, tags: ["finance"] }, - { tool: tonGetBalanceTool, executor: tonGetBalanceExecutor, tags: ["finance"] }, - { tool: tonPriceTool, executor: tonPriceExecutor, tags: ["finance"] }, - { tool: tonGetTransactionsTool, executor: tonGetTransactionsExecutor, tags: ["finance"] }, - { tool: tonMyTransactionsTool, executor: tonMyTransactionsExecutor, tags: ["finance"] }, - { tool: tonChartTool, executor: tonChartExecutor, tags: ["finance"] }, - { tool: nftListTool, executor: nftListExecutor, tags: ["finance"] }, - { tool: jettonSendTool, executor: jettonSendExecutor, scope: "dm-only", tags: ["finance"] }, - { tool: jettonBalancesTool, executor: jettonBalancesExecutor, tags: ["finance"] }, - { tool: jettonInfoTool, executor: jettonInfoExecutor, tags: ["finance"] }, - { tool: jettonPriceTool, executor: jettonPriceExecutor, tags: ["finance"] }, - { tool: jettonHoldersTool, executor: jettonHoldersExecutor, tags: ["finance"] }, - { tool: jettonHistoryTool, executor: jettonHistoryExecutor, tags: ["finance"] }, - { tool: dexQuoteTool, executor: dexQuoteExecutor, tags: ["finance"] }, + { + tool: tonSendTool, + executor: tonSendExecutor, + scope: "dm-only", + mode: "both", + tags: ["finance"], + }, + { tool: tonGetAddressTool, executor: tonGetAddressExecutor, mode: "both", tags: ["finance"] }, + { tool: tonGetBalanceTool, executor: tonGetBalanceExecutor, mode: "both", tags: ["finance"] }, + { tool: tonPriceTool, executor: tonPriceExecutor, mode: "both", tags: ["finance"] }, + { + tool: tonGetTransactionsTool, + executor: tonGetTransactionsExecutor, + mode: "both", + tags: ["finance"], + }, + { + tool: tonMyTransactionsTool, + executor: tonMyTransactionsExecutor, + mode: "both", + tags: ["finance"], + }, + { tool: tonChartTool, executor: tonChartExecutor, mode: "both", tags: ["finance"] }, + { tool: nftListTool, executor: nftListExecutor, mode: "both", tags: ["finance"] }, + { + tool: jettonSendTool, + executor: jettonSendExecutor, + scope: "dm-only", + mode: "both", + tags: ["finance"], + }, + { tool: jettonBalancesTool, executor: jettonBalancesExecutor, mode: "both", tags: ["finance"] }, + { tool: jettonInfoTool, executor: jettonInfoExecutor, mode: "both", tags: ["finance"] }, + { tool: jettonPriceTool, executor: jettonPriceExecutor, mode: "both", tags: ["finance"] }, + { tool: jettonHoldersTool, executor: jettonHoldersExecutor, mode: "both", tags: ["finance"] }, + { tool: jettonHistoryTool, executor: jettonHistoryExecutor, mode: "both", tags: ["finance"] }, + { tool: dexQuoteTool, executor: dexQuoteExecutor, mode: "both", tags: ["finance"] }, ]; diff --git a/src/agent/tools/types.ts b/src/agent/tools/types.ts index 188ac9c5..d6a0fdce 100644 --- a/src/agent/tools/types.ts +++ b/src/agent/tools/types.ts @@ -57,6 +57,16 @@ export type ToolScope = | "allowlist" | "disabled"; +/** + * Telegram execution mode a tool supports. + * - "user": userbot only — relies on an MTProto capability the Bot API lacks + * - "bot": Bot API only — relies on a capability exclusive to bots + * - "both": works identically in either mode + * + * Mandatory on every built-in tool: the compiler refuses an undeclared tool. + */ +export type ToolMode = "user" | "bot" | "both"; + /** * Tool definition compatible with pi-ai */ @@ -96,8 +106,8 @@ export interface ToolEntry { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- tool executors accept varied param shapes executor: ToolExecutor; scope?: ToolScope; - /** When set to "user", excluded in bot mode. When set to "bot", excluded in user mode. */ - requiredMode?: "user" | "bot"; + /** Telegram mode(s) this tool runs in. Mandatory — every tool must declare it. */ + mode: ToolMode; /** Toolset tags for profile-based filtering (e.g. "core", "finance", "social") */ tags?: string[]; } @@ -120,6 +130,8 @@ export interface PluginModule { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- tool executors accept varied param shapes executor: ToolExecutor; scope?: ToolScope; + /** Telegram mode(s) this module tool runs in. Defaults to "both" when omitted. */ + mode?: ToolMode; }>; /** Start background jobs (polling, timers, etc.) */ start?(context: PluginContext): Promise; diff --git a/src/agent/tools/web/index.ts b/src/agent/tools/web/index.ts index 9aa0a7fd..bbf3e6c0 100644 --- a/src/agent/tools/web/index.ts +++ b/src/agent/tools/web/index.ts @@ -8,6 +8,6 @@ export { webSearchTool, webSearchExecutor }; export { webFetchTool, webFetchExecutor }; export const tools: ToolEntry[] = [ - { tool: webSearchTool, executor: webSearchExecutor, tags: ["web"] }, - { tool: webFetchTool, executor: webFetchExecutor, tags: ["web"] }, + { tool: webSearchTool, executor: webSearchExecutor, mode: "both", tags: ["web"] }, + { tool: webFetchTool, executor: webFetchExecutor, mode: "both", tags: ["web"] }, ]; diff --git a/src/agent/tools/workspace/index.ts b/src/agent/tools/workspace/index.ts index 80f7c46b..a1767e90 100644 --- a/src/agent/tools/workspace/index.ts +++ b/src/agent/tools/workspace/index.ts @@ -20,21 +20,24 @@ export const tools: ToolEntry[] = [ tool: workspaceWriteTool, executor: workspaceWriteExecutor, scope: "dm-only", + mode: "both", tags: ["workspace"], }, { tool: workspaceDeleteTool, executor: workspaceDeleteExecutor, scope: "dm-only", + mode: "both", tags: ["workspace"], }, { tool: workspaceRenameTool, executor: workspaceRenameExecutor, scope: "dm-only", + mode: "both", tags: ["workspace"], }, - { tool: workspaceListTool, executor: workspaceListExecutor, tags: ["workspace"] }, - { tool: workspaceReadTool, executor: workspaceReadExecutor, tags: ["workspace"] }, - { tool: workspaceInfoTool, executor: workspaceInfoExecutor, tags: ["workspace"] }, + { tool: workspaceListTool, executor: workspaceListExecutor, mode: "both", tags: ["workspace"] }, + { tool: workspaceReadTool, executor: workspaceReadExecutor, mode: "both", tags: ["workspace"] }, + { tool: workspaceInfoTool, executor: workspaceInfoExecutor, mode: "both", tags: ["workspace"] }, ]; diff --git a/src/deals/module.ts b/src/deals/module.ts index dde71482..8b2c19f5 100644 --- a/src/deals/module.ts +++ b/src/deals/module.ts @@ -50,23 +50,35 @@ const dealsModule: PluginModule = { tools(config) { if (!config.deals?.enabled) return []; + // Deals run on the GramJS DealBot — userbot only (skipped in bot mode). return [ { tool: dealProposeTool, executor: withDealsDb(dealProposeExecutor), scope: "dm-only" as const, + mode: "user" as const, }, { tool: dealVerifyPaymentTool, executor: withDealsDb(dealVerifyPaymentExecutor), scope: "dm-only" as const, + mode: "user" as const, + }, + { + tool: dealStatusTool, + executor: withDealsDb(dealStatusExecutor), + mode: "user" as const, + }, + { + tool: dealListTool, + executor: withDealsDb(dealListExecutor), + mode: "user" as const, }, - { tool: dealStatusTool, executor: withDealsDb(dealStatusExecutor) }, - { tool: dealListTool, executor: withDealsDb(dealListExecutor) }, { tool: dealCancelTool, executor: withDealsDb(dealCancelExecutor), scope: "dm-only" as const, + mode: "user" as const, }, ]; }, diff --git a/src/sdk/telegram-utils.ts b/src/sdk/telegram-utils.ts index dee917be..c509458e 100644 --- a/src/sdk/telegram-utils.ts +++ b/src/sdk/telegram-utils.ts @@ -13,6 +13,11 @@ export function requireBridge(bridge: ITelegramBridge): void { } export function getClient(bridge: ITelegramBridge) { + if (bridge.getMode() !== "user") { + throw new Error( + "This tool requires user mode — it relies on an MTProto capability the Bot API does not provide." + ); + } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- user-only escape hatch, cast to GramJS client return (bridge.getRawClient() as any).getClient(); } diff --git a/src/sdk/telegram.ts b/src/sdk/telegram.ts index fc49cd39..c405d782 100644 --- a/src/sdk/telegram.ts +++ b/src/sdk/telegram.ts @@ -97,6 +97,7 @@ export function createTelegramSDK( }, async getMessages(chatId, limit): Promise { + requireUserMode("getMessages"); requireBridge(); try { const messages = await bridge.getMessages(chatId, limit ?? 50); diff --git a/src/telegram/bridges/bot.ts b/src/telegram/bridges/bot.ts index 0fec64ad..f5887ebc 100644 --- a/src/telegram/bridges/bot.ts +++ b/src/telegram/bridges/bot.ts @@ -387,7 +387,9 @@ export class GrammyBotBridge implements ITelegramBridge { } async getMessages(_chatId: string, _limit: number): Promise { - return []; + throw new Error( + "getMessages is unavailable in bot mode — bots cannot read arbitrary chat history." + ); } parseMessage(msg: GrammyMessage): TelegramMessage { From 15b051bc6d3bddeb6339f2b5e16ef50c3b006cc3 Mon Sep 17 00:00:00 2001 From: TONresistor Date: Fri, 22 May 2026 03:48:09 +0200 Subject: [PATCH 002/151] fix(telegram): remove getRawClient escape hatch, fix 2 latent bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getRawClient() returned the TelegramUserClient wrapper typed as unknown. pin.ts (unpin) and deals/executor.ts (gift transfer) cast it and called .invoke()/.getInputEntity() — methods the wrapper does not expose — which would throw at runtime. The as-any casts masked the mismatch. - drop getRawClient() and getPeer() from the ITelegramBridge interface - reach the GramJS client through the typed getClient() + isUserBridge guard - pin.ts and deals/executor.ts now use the getClient() helper (real client) - verify-payment / verification-poller / task-resolver use interface methods (getOwnUserId, sendMessage) instead of the loosely-typed raw client --- src/agent/tools/deals/verify-payment.ts | 10 ++++----- .../__tests__/check-channel-username.test.ts | 2 +- .../__tests__/create-channel-username.test.ts | 2 +- .../__tests__/set-channel-username.test.ts | 2 +- src/agent/tools/telegram/chats/get-history.ts | 3 ++- .../messaging/__tests__/inline-send.test.ts | 2 +- src/agent/tools/telegram/messaging/pin.ts | 4 ++-- src/bot/services/verification-poller.ts | 7 +++--- src/deals/executor.ts | 4 ++-- src/sdk/__tests__/telegram-social.test.ts | 8 +++---- src/sdk/telegram-utils.ts | 6 ++--- src/sdk/telegram.ts | 7 +++--- src/telegram/bridge-interface.ts | 4 ---- src/telegram/bridges/bot.ts | 8 ------- src/telegram/bridges/user.ts | 5 +---- src/telegram/callbacks/handler.ts | 6 +++-- src/telegram/task-dependency-resolver.ts | 22 +++++++++---------- 17 files changed, 44 insertions(+), 58 deletions(-) diff --git a/src/agent/tools/deals/verify-payment.ts b/src/agent/tools/deals/verify-payment.ts index 84d62c0b..43d7b178 100644 --- a/src/agent/tools/deals/verify-payment.ts +++ b/src/agent/tools/deals/verify-payment.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import { Type } from "@sinclair/typebox"; import type { Tool, ToolExecutor, ToolResult } from "../types.js"; import type { Deal } from "../../../deals/types.js"; @@ -165,18 +164,17 @@ export const dealVerifyPaymentExecutor: ToolExecutor = log.info(`[Deal] Checking for gift receipt for deal #${params.dealId}...`); - // Use GiftDetector to poll for new gifts - // Note: We need to pass the agent's own user ID (bot's Telegram ID) - const me = (context.bridge.getRawClient() as any).getMe(); + // Use GiftDetector to poll for new gifts — needs the agent's own Telegram ID + const ownUserId = context.bridge.getOwnUserId(); - if (!me) { + if (!ownUserId) { return { success: false, error: "Failed to get bot user info. Bot may not be authenticated.", }; } - const botUserId = Number(me.id); + const botUserId = Number(ownUserId); const giftDetector = new GiftDetector(); const newGifts = await giftDetector.detectNewGifts(botUserId, context); diff --git a/src/agent/tools/telegram/chats/__tests__/check-channel-username.test.ts b/src/agent/tools/telegram/chats/__tests__/check-channel-username.test.ts index 36521f99..8486758a 100644 --- a/src/agent/tools/telegram/chats/__tests__/check-channel-username.test.ts +++ b/src/agent/tools/telegram/chats/__tests__/check-channel-username.test.ts @@ -8,7 +8,7 @@ const mockGetEntity = vi.fn(); const mockContext = { bridge: { getMode: () => "user", - getRawClient: () => ({ + getClient: () => ({ getClient: () => ({ invoke: mockInvoke, getEntity: mockGetEntity, diff --git a/src/agent/tools/telegram/chats/__tests__/create-channel-username.test.ts b/src/agent/tools/telegram/chats/__tests__/create-channel-username.test.ts index 482707f7..ef72d6dc 100644 --- a/src/agent/tools/telegram/chats/__tests__/create-channel-username.test.ts +++ b/src/agent/tools/telegram/chats/__tests__/create-channel-username.test.ts @@ -7,7 +7,7 @@ const mockInvoke = vi.fn(); const mockContext = { bridge: { getMode: () => "user", - getRawClient: () => ({ + getClient: () => ({ getClient: () => ({ invoke: mockInvoke, }), diff --git a/src/agent/tools/telegram/chats/__tests__/set-channel-username.test.ts b/src/agent/tools/telegram/chats/__tests__/set-channel-username.test.ts index cb4d32ed..2d9251e8 100644 --- a/src/agent/tools/telegram/chats/__tests__/set-channel-username.test.ts +++ b/src/agent/tools/telegram/chats/__tests__/set-channel-username.test.ts @@ -8,7 +8,7 @@ const mockGetEntity = vi.fn(); const mockContext = { bridge: { getMode: () => "user", - getRawClient: () => ({ + getClient: () => ({ getClient: () => ({ invoke: mockInvoke, getEntity: mockGetEntity, diff --git a/src/agent/tools/telegram/chats/get-history.ts b/src/agent/tools/telegram/chats/get-history.ts index 7c7d5186..c75256cc 100644 --- a/src/agent/tools/telegram/chats/get-history.ts +++ b/src/agent/tools/telegram/chats/get-history.ts @@ -5,6 +5,7 @@ import type { Tool, ToolExecutor, ToolResult } from "../../types.js"; import { getErrorMessage } from "../../../../utils/errors.js"; import { createLogger } from "../../../../utils/logger.js"; import { getClient } from "../../../../sdk/telegram-utils.js"; +import { isUserBridge } from "../../../../telegram/bridge-guards.js"; const log = createLogger("Tools"); @@ -69,7 +70,7 @@ export const telegramGetHistoryExecutor: ToolExecutor = async const gramJsClient = getClient(context.bridge); // Use cached peer if available, fall back to raw chatId string - const entity = context.bridge.getPeer(chatId) || chatId; + const entity = isUserBridge(context.bridge) ? context.bridge.getPeer(chatId) || chatId : chatId; // Fetch messages using GramJS getMessages const messages = await gramJsClient.getMessages(entity, { diff --git a/src/agent/tools/telegram/messaging/__tests__/inline-send.test.ts b/src/agent/tools/telegram/messaging/__tests__/inline-send.test.ts index 12fe53ef..2f9f2ebc 100644 --- a/src/agent/tools/telegram/messaging/__tests__/inline-send.test.ts +++ b/src/agent/tools/telegram/messaging/__tests__/inline-send.test.ts @@ -17,7 +17,7 @@ describe("bot_inline_send", () => { const mockBridge = { isAvailable: () => true, getMode: () => "user", - getRawClient: () => ({ + getClient: () => ({ getClient: () => mockGramJsClient, }), }; diff --git a/src/agent/tools/telegram/messaging/pin.ts b/src/agent/tools/telegram/messaging/pin.ts index 04e98124..89c0e6c7 100644 --- a/src/agent/tools/telegram/messaging/pin.ts +++ b/src/agent/tools/telegram/messaging/pin.ts @@ -5,10 +5,10 @@ import { Type } from "@sinclair/typebox"; import { Api } from "telegram"; -import type { TelegramClient } from "telegram"; import type { Tool, ToolExecutor, ToolResult } from "../../types.js"; import { getErrorMessage } from "../../../../utils/errors.js"; import { createLogger } from "../../../../utils/logger.js"; +import { getClient } from "../../../../sdk/telegram-utils.js"; const log = createLogger("Tools"); @@ -103,7 +103,7 @@ export const telegramUnpinMessageExecutor: ToolExecutor = as try { const { chat_id, message_id, unpin_all = false } = params; - const client = context.bridge.getRawClient() as TelegramClient; + const client = getClient(context.bridge); if (unpin_all) { await client.invoke( diff --git a/src/bot/services/verification-poller.ts b/src/bot/services/verification-poller.ts index 9426ab09..fd97b153 100644 --- a/src/bot/services/verification-poller.ts +++ b/src/bot/services/verification-poller.ts @@ -187,11 +187,10 @@ export class VerificationPoller { ): Promise<{ verified: boolean; giftMsgId?: string }> { try { // Get agent's own user ID - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- user-only MTProto path - const me = (this.bridge.getRawClient() as any)?.getMe?.(); - if (!me) return { verified: false }; + const ownUserId = this.bridge.getOwnUserId(); + if (!ownUserId) return { verified: false }; - const botUserId = Number(me.id); + const botUserId = Number(ownUserId); // Import gift executor const { telegramGetMyGiftsExecutor } = diff --git a/src/deals/executor.ts b/src/deals/executor.ts index 7af7c90a..a65b88bb 100644 --- a/src/deals/executor.ts +++ b/src/deals/executor.ts @@ -10,6 +10,7 @@ import { sendTon } from "../ton/transfer.js"; import { formatAsset } from "./utils.js"; import { JournalStore } from "../memory/journal-store.js"; import { getErrorMessage } from "../utils/errors.js"; +import { getClient } from "../sdk/telegram-utils.js"; import { createLogger } from "../utils/logger.js"; const log = createLogger("Deal"); @@ -144,8 +145,7 @@ Thank you for trading! 🎉`, ); // Transfer collectible gift using Telegram API - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- user-only MTProto path - const gramJsClient = bridge.getRawClient() as any; + const gramJsClient = getClient(bridge); const Api = (await import("telegram")).Api; try { diff --git a/src/sdk/__tests__/telegram-social.test.ts b/src/sdk/__tests__/telegram-social.test.ts index 3432f96e..61af8ef0 100644 --- a/src/sdk/__tests__/telegram-social.test.ts +++ b/src/sdk/__tests__/telegram-social.test.ts @@ -290,9 +290,9 @@ describe("createTelegramSocialSDK", () => { }); it("returns null on unexpected top-level error, logs it", async () => { - // Make getRawClient throw to hit the outer catch - const originalGetRawClient = mockBridge.getRawClient; - mockBridge.getRawClient = () => { + // Make getClient throw to hit the outer catch + const originalGetClient = mockBridge.getClient; + mockBridge.getClient = () => { throw new Error("unexpected"); }; @@ -302,7 +302,7 @@ describe("createTelegramSocialSDK", () => { expect(result).toBeNull(); expect(mockLog.error).toHaveBeenCalled(); - mockBridge.getRawClient = originalGetRawClient; + mockBridge.getClient = originalGetClient; }); }); diff --git a/src/sdk/telegram-utils.ts b/src/sdk/telegram-utils.ts index c509458e..2a8d2436 100644 --- a/src/sdk/telegram-utils.ts +++ b/src/sdk/telegram-utils.ts @@ -1,4 +1,5 @@ import type { ITelegramBridge } from "../telegram/bridge-interface.js"; +import { isUserBridge } from "../telegram/bridge-guards.js"; import type { Api } from "telegram"; import type { SimpleMessage } from "@teleton-agent/sdk"; import { PluginSDKError } from "@teleton-agent/sdk"; @@ -13,13 +14,12 @@ export function requireBridge(bridge: ITelegramBridge): void { } export function getClient(bridge: ITelegramBridge) { - if (bridge.getMode() !== "user") { + if (!isUserBridge(bridge)) { throw new Error( "This tool requires user mode — it relies on an MTProto capability the Bot API does not provide." ); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- user-only escape hatch, cast to GramJS client - return (bridge.getRawClient() as any).getClient(); + return bridge.getClient().getClient(); } /** Convert a GramJS message to a SimpleMessage */ diff --git a/src/sdk/telegram.ts b/src/sdk/telegram.ts index c405d782..2ca7cfff 100644 --- a/src/sdk/telegram.ts +++ b/src/sdk/telegram.ts @@ -1,5 +1,5 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import type { ITelegramBridge } from "../telegram/bridge-interface.js"; +import { isUserBridge } from "../telegram/bridge-guards.js"; import type { TelegramSDK, TelegramUser, SimpleMessage, PluginLogger } from "@teleton-agent/sdk"; import { PluginSDKError } from "@teleton-agent/sdk"; import { getErrorMessage } from "../utils/errors.js"; @@ -117,7 +117,8 @@ export function createTelegramSDK( getMe(): TelegramUser | null { requireUserMode("getMe"); try { - const me = (bridge.getRawClient() as any)?.getMe?.(); + if (!isUserBridge(bridge)) return null; + const me = bridge.getClient().getMe(); if (!me) return null; return { id: Number(me.id), @@ -139,7 +140,7 @@ export function createTelegramSDK( log.warn("getRawClient() called — this bypasses SDK sandbox guarantees"); if (!bridge.isAvailable()) return null; try { - return bridge.getRawClient(); + return isUserBridge(bridge) ? bridge.getClient() : null; } catch { return null; } diff --git a/src/telegram/bridge-interface.ts b/src/telegram/bridge-interface.ts index 96fb2d73..5060223c 100644 --- a/src/telegram/bridge-interface.ts +++ b/src/telegram/bridge-interface.ts @@ -112,8 +112,4 @@ export interface ITelegramBridge { filters?: { incoming?: boolean; outgoing?: boolean; chats?: string[] } ): void; fetchReplyContext(rawMsg: unknown): Promise; - - // Escape hatches (user-only tools) - getPeer(chatId: string): unknown | undefined; - getRawClient(): unknown; } diff --git a/src/telegram/bridges/bot.ts b/src/telegram/bridges/bot.ts index f5887ebc..5c5875ff 100644 --- a/src/telegram/bridges/bot.ts +++ b/src/telegram/bridges/bot.ts @@ -531,14 +531,6 @@ export class GrammyBotBridge implements ITelegramBridge { }; } - getPeer(_chatId: string): undefined { - return undefined; - } - - getRawClient(): Bot { - return this.bot; - } - /** Set callback handler for synthetic message injection (from CallbackRouter) */ setCallbackHandler(handler: (msg: TelegramMessage) => void): void { this.callbackHandler = handler; diff --git a/src/telegram/bridges/user.ts b/src/telegram/bridges/user.ts index 43492a3d..140aff5f 100644 --- a/src/telegram/bridges/user.ts +++ b/src/telegram/bridges/user.ts @@ -477,12 +477,9 @@ export class GramJSUserBridge implements ITelegramBridge { return this.peerCache.get(chatId); } - getRawClient(): unknown { - return this.client; - } - // --- Non-interface methods (user-bridge specific) --- + /** The GramJS client wrapper. Reach it through the isUserBridge type guard. */ getClient(): TelegramUserClient { return this.client; } diff --git a/src/telegram/callbacks/handler.ts b/src/telegram/callbacks/handler.ts index 75c0739b..5e102885 100644 --- a/src/telegram/callbacks/handler.ts +++ b/src/telegram/callbacks/handler.ts @@ -1,4 +1,5 @@ import type { ITelegramBridge } from "../bridge-interface.js"; +import { isUserBridge } from "../bridge-guards.js"; import { createLogger } from "../../utils/logger.js"; const log = createLogger("Telegram"); @@ -68,8 +69,9 @@ export class CallbackQueryHandler { private async answerCallback(queryId: bigint, message?: string, alert = false): Promise { try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- user-only MTProto callback answer - await (this.bridge.getRawClient() as any)?.answerCallbackQuery?.(queryId, { message, alert }); + if (isUserBridge(this.bridge)) { + await this.bridge.getClient().answerCallbackQuery(queryId, { message, alert }); + } } catch (error) { log.error({ err: error }, "Error answering callback"); } diff --git a/src/telegram/task-dependency-resolver.ts b/src/telegram/task-dependency-resolver.ts index 3a9a40c0..aee1259c 100644 --- a/src/telegram/task-dependency-resolver.ts +++ b/src/telegram/task-dependency-resolver.ts @@ -187,17 +187,17 @@ export class TaskDependencyResolver { log.warn(`↳ Cannot trigger [TASK:${taskId}]: no admin_id configured in bot mode`); } } else { - // User mode: send to Saved Messages via GramJS - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- user-only MTProto path - const gramJsClient = this.bridge.getRawClient() as any; - const me = await gramJsClient.getMe(); - - // Send task message immediately (no scheduling) - await gramJsClient.sendMessage(me, { - message: `[TASK:${taskId}] ${task.description}`, - }); - - log.info(`↳ Sent [TASK:${taskId}] to Saved Messages`); + // User mode: send to Saved Messages (the agent's own chat) + const ownId = this.bridge.getOwnUserId(); + if (ownId) { + await this.bridge.sendMessage({ + chatId: String(ownId), + text: `[TASK:${taskId}] ${task.description}`, + }); + log.info(`↳ Sent [TASK:${taskId}] to Saved Messages`); + } else { + log.warn(`↳ Cannot trigger [TASK:${taskId}]: own user id unavailable`); + } } } catch (error) { log.error({ err: error }, `Error triggering task ${taskId}`); From c3d49d06d8da121fa8fc15f118c7c70142e7a891 Mon Sep 17 00:00:00 2001 From: TONresistor Date: Sat, 23 May 2026 05:41:27 +0200 Subject: [PATCH 003/151] refactor(bridge): replace scattered mode checks with requiresOffsetDedup() capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The handler's offset-store dedup is needed when the bridge can redeliver the same message (GramJS user mode). Bot mode dedupes via update_id and does not need it. Express this as a bridge capability instead of checking getMode() at four sites in handlers.ts. The streaming gate also drops a redundant mode check — bridge.streamResponse alone is enough since it exists only on bridges that can stream. Declare streamDraft / clearDraft / finalizeDraft / resetDraft as optional methods on ITelegramBridge so future user-mode streaming (Phase 3) will not need new interface surface. --- src/agent/runtime.ts | 5 +++++ src/cli/commands/onboard.ts | 2 ++ src/config/configurable-keys.ts | 11 ++++++++++ src/config/schema.ts | 4 ++++ src/index.ts | 23 ++++++++++++++++++++ src/telegram/__tests__/handlers.test.ts | 1 + src/telegram/admin.ts | 29 +++++++++++++++++++++++++ src/telegram/bridge-interface.ts | 14 +++++++++++- src/telegram/bridges/bot.ts | 27 +++++++++++++++++++++++ src/telegram/bridges/user.ts | 4 ++++ src/telegram/handlers.ts | 16 ++++++-------- 11 files changed, 126 insertions(+), 10 deletions(-) diff --git a/src/agent/runtime.ts b/src/agent/runtime.ts index 87d3b396..89e6ae6f 100644 --- a/src/agent/runtime.ts +++ b/src/agent/runtime.ts @@ -95,6 +95,7 @@ export interface ProcessMessageOptions { messageId?: number; replyContext?: { senderName?: string; text: string; isAgent?: boolean }; isHeartbeat?: boolean; + isGuest?: boolean; streamToChat?: { chatId: string; bridge: ITelegramBridge; mode: "all" | "replace" | "off" }; } @@ -662,6 +663,10 @@ export class AgentRuntime { } } + if (opts.isGuest && tools) { + tools = tools.filter((t) => !TELEGRAM_SEND_TOOLS.has(t.name)); + } + return { kind: "ready", turn: { diff --git a/src/cli/commands/onboard.ts b/src/cli/commands/onboard.ts index aeef5e7a..6862ab00 100644 --- a/src/cli/commands/onboard.ts +++ b/src/cli/commands/onboard.ts @@ -1096,6 +1096,7 @@ async function runInteractiveOnboarding( bot_token: botToken, bot_username: botUsername, stream_mode: "all", + guest_mode: false, }, storage: { sessions_file: `${workspace.root}/sessions.json`, @@ -1307,6 +1308,7 @@ async function runNonInteractiveOnboarding( bot_token: nonInteractiveMode === "bot" ? options.botToken : undefined, bot_username: undefined, stream_mode: "all", + guest_mode: false, }, storage: { sessions_file: `${workspace.root}/sessions.json`, diff --git a/src/config/configurable-keys.ts b/src/config/configurable-keys.ts index a34e8593..bc169fd0 100644 --- a/src/config/configurable-keys.ts +++ b/src/config/configurable-keys.ts @@ -457,6 +457,17 @@ export const CONFIGURABLE_KEYS: Record = { mask: identity, parse: (v) => Number(v), }, + "telegram.guest_mode": { + type: "boolean", + category: "Telegram", + label: "Guest Mode", + description: "Answer guest queries in chats the bot is not a member of", + sensitive: false, + hotReload: "instant", + validate: enumValidator(["true", "false"]), + mask: identity, + parse: (v) => v === "true", + }, // ─── Embedding ───────────────────────────────────────────────────── "embedding.provider": { diff --git a/src/config/schema.ts b/src/config/schema.ts index 09827664..b8f439fc 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -105,6 +105,10 @@ export const TelegramConfigSchema = z .describe( "Bot streaming mode: replace=each iteration replaces draft (default), all=concatenate all iterations, off=no streaming" ), + guest_mode: z + .boolean() + .default(false) + .describe("Allow the bot to answer guest queries in chats it is not a member of"), }) .superRefine((data, ctx) => { if (data.mode === "user") { diff --git a/src/index.ts b/src/index.ts index af696894..80e26294 100644 --- a/src/index.ts +++ b/src/index.ts @@ -207,6 +207,7 @@ export class TeletonApp { this.bridge, this.config.telegram, this.agent, + this.configPath, modulePermissions, this.toolRegistry ); @@ -366,6 +367,7 @@ ${blue} ┌────────────────────── this.bridge, this.config.telegram, this.agent, + this.configPath, modulePermissions, this.toolRegistry ); @@ -609,6 +611,27 @@ ${blue} ┌────────────────────── void this.debouncer!.enqueue(msg); }); if (firstStart) { + this.bridge.onGuestMessage(async (msg) => { + if (!this.config.telegram.guest_mode) return ""; + if (this.adminHandler.isPaused()) return ""; + const response = await this.agent.processMessage({ + chatId: `telegram:guest:${msg.chatId}`, + userMessage: msg.text, + userName: msg.senderFirstName, + senderUsername: msg.senderUsername, + isGroup: true, + isGuest: true, + timestamp: msg.timestamp.getTime(), + messageId: msg.id, + toolContext: { + bridge: this.bridge, + db: getDatabase().getDb(), + senderId: msg.senderId, + config: this.config, + }, + }); + return response.content; + }); this.bridge.startPolling(); } void this.bridge.syncCommands(); diff --git a/src/telegram/__tests__/handlers.test.ts b/src/telegram/__tests__/handlers.test.ts index 2cc60330..af125ccb 100644 --- a/src/telegram/__tests__/handlers.test.ts +++ b/src/telegram/__tests__/handlers.test.ts @@ -95,6 +95,7 @@ function makeBridge() { setTyping: vi.fn().mockResolvedValue(undefined), fetchReplyContext: vi.fn().mockResolvedValue(null), getMode: vi.fn().mockReturnValue("user"), + requiresOffsetDedup: vi.fn().mockReturnValue(true), } as any; } diff --git a/src/telegram/admin.ts b/src/telegram/admin.ts index 7d1fe7ca..3e788c9b 100644 --- a/src/telegram/admin.ts +++ b/src/telegram/admin.ts @@ -11,6 +11,8 @@ const log = createLogger("Telegram"); import type { ModulePermissions, ModuleLevel } from "../agent/tools/module-permissions.js"; import type { ToolRegistry } from "../agent/tools/registry.js"; import { writePluginSecret, deletePluginSecret, listPluginSecretKeys } from "../sdk/secrets.js"; +import { readRawConfig, writeRawConfig, setNestedValue } from "../config/configurable-keys.js"; +import { getErrorMessage } from "../utils/errors.js"; export interface AdminCommand { command: string; @@ -30,17 +32,20 @@ export class AdminHandler { private paused = false; private permissions: ModulePermissions | null; private registry: ToolRegistry | null; + private configPath: string; constructor( bridge: ITelegramBridge, config: TelegramConfig, agent: AgentRuntime, + configPath: string, permissions?: ModulePermissions, registry?: ToolRegistry ) { this.bridge = bridge; this.config = config; this.agent = agent; + this.configPath = configPath; this.permissions = permissions ?? null; this.registry = registry ?? null; } @@ -109,6 +114,8 @@ export class AdminHandler { return this.handleVerboseCommand(); case "rag": return this.handleRagCommand(command); + case "guest": + return this.handleGuestCommand(command); case "modules": return this.handleModulesCommand(command, isGroup ?? false); case "plugin": @@ -322,6 +329,25 @@ export class AdminHandler { return next ? "🔍 Tool RAG **ON**" : "🔇 Tool RAG **OFF**"; } + private handleGuestCommand(command: AdminCommand): string { + const cfg = this.agent.getConfig(); + const sub = command.args[0]?.toLowerCase(); + if (sub !== "on" && sub !== "off") { + const state = cfg.telegram.guest_mode ? "ON" : "OFF"; + return `👤 Guest mode: **${state}**\n\nUsage: /guest on|off`; + } + const enabled = sub === "on"; + try { + const raw = readRawConfig(this.configPath); + setNestedValue(raw, "telegram.guest_mode", enabled); + writeRawConfig(raw, this.configPath); + } catch (error) { + return `❌ Error saving config: ${getErrorMessage(error)}`; + } + cfg.telegram.guest_mode = enabled; + return enabled ? "👤 Guest mode **ON**" : "👤 Guest mode **OFF**"; + } + private handleModulesCommand(command: AdminCommand, isGroup: boolean): string { if (!this.permissions || !this.registry) { return "❌ Module permissions not available"; @@ -558,6 +584,9 @@ Toggle verbose debug logging **/rag** [status|topk ] Toggle Tool RAG or view status +**/guest** on|off +Toggle guest mode (answer queries in non-member chats) + **/pause** / **/resume** Pause or resume the agent diff --git a/src/telegram/bridge-interface.ts b/src/telegram/bridge-interface.ts index 5060223c..b640a749 100644 --- a/src/telegram/bridge-interface.ts +++ b/src/telegram/bridge-interface.ts @@ -103,8 +103,20 @@ export interface ITelegramBridge { // Chat info getChatInfo(chatId: string): Promise; - /** Stream a response token by token via message drafts (bot mode). Returns final sent message. */ + // Capabilities + /** True when the handler must dedup messages via the offset store (user mode redelivers; bot mode dedupes via update_id). */ + requiresOffsetDedup(): boolean; + + /** Stream a response token by token via message drafts. Returns the final sent message. */ streamResponse?(chatId: string, textStream: AsyncIterable): Promise; + /** Push a chunk to a streaming draft. Returns the un-sent remainder. */ + streamDraft?(chatId: string, textStream: AsyncIterable): Promise; + /** Clear an active streaming draft. */ + clearDraft?(chatId: string): Promise; + /** Send the final draft as a real message. */ + finalizeDraft?(chatId: string, text: string): Promise; + /** Reset draft state for the next iteration. */ + resetDraft?(chatId: string): void; // Events onNewMessage( diff --git a/src/telegram/bridges/bot.ts b/src/telegram/bridges/bot.ts index 5c5875ff..db88134e 100644 --- a/src/telegram/bridges/bot.ts +++ b/src/telegram/bridges/bot.ts @@ -76,6 +76,10 @@ export class GrammyBotBridge implements ITelegramBridge { return "bot"; } + requiresOffsetDedup(): boolean { + return false; + } + isAvailable(): boolean { return this.connected; } @@ -514,6 +518,28 @@ export class GrammyBotBridge implements ITelegramBridge { }); } + /** Register a handler for Bot API 10.0 guest queries. Reply text is sent via answerGuestQuery. */ + onGuestMessage(handler: (msg: TelegramMessage) => Promise): void { + this.bot.on("guest_message", async (ctx) => { + const gm = ctx.guestMessage; + if (!gm) return; + try { + const content = await handler(this.parseMessage(gm)); + const text = content?.trim(); + if (!text || text === "__SILENT__") return; + const html = markdownToTelegramHtml(text).slice(0, TELEGRAM_MAX_MESSAGE_LENGTH); + await ctx.answerGuestQuery({ + type: "article", + id: String(gm.message_id), + title: this.botInfo?.firstName ?? "Reply", + input_message_content: { message_text: html, parse_mode: "HTML" }, + }); + } catch (err) { + log.error({ err }, "Error in guest message handler"); + } + }); + } + async fetchReplyContext(rawMsg: unknown): Promise { const msg = rawMsg as GrammyMessage | undefined; if (!msg?.reply_to_message) return null; @@ -549,6 +575,7 @@ export class GrammyBotBridge implements ITelegramBridge { { command: "wallet", description: "Check TON wallet balance" }, { command: "verbose", description: "Toggle verbose logging" }, { command: "rag", description: "Toggle Tool RAG or view status" }, + { command: "guest", description: "Toggle guest mode" }, { command: "pause", description: "Pause the agent" }, { command: "resume", description: "Resume the agent" }, { command: "stop", description: "Emergency shutdown" }, diff --git a/src/telegram/bridges/user.ts b/src/telegram/bridges/user.ts index 140aff5f..55d70ada 100644 --- a/src/telegram/bridges/user.ts +++ b/src/telegram/bridges/user.ts @@ -34,6 +34,10 @@ export class GramJSUserBridge implements ITelegramBridge { return "user"; } + requiresOffsetDedup(): boolean { + return true; + } + async connect(): Promise { await this.client.connect(); const me = this.client.getMe(); diff --git a/src/telegram/handlers.ts b/src/telegram/handlers.ts index 88ee7ff5..57f25f56 100644 --- a/src/telegram/handlers.ts +++ b/src/telegram/handlers.ts @@ -201,8 +201,8 @@ export class MessageHandler { analyzeMessage(message: TelegramMessage): MessageContext { const isAdmin = this.config.admin_ids.includes(message.senderId); - // Skip offset dedup in bot mode — Grammy handles dedup via update_id internally - if (this.bridge.getMode() !== "bot") { + // Bridges that redeliver (user mode) need handler-side dedup; bot mode dedupes via update_id. + if (this.bridge.requiresOffsetDedup()) { const chatOffset = readOffset(message.chatId) ?? 0; if (message.id <= chatOffset) { return { @@ -391,9 +391,8 @@ export class MessageHandler { await this.chatQueue.enqueue(message.chatId, async () => { try { // Re-check offset after queue wait to prevent duplicate processing - // (GramJS may fire duplicate NewMessage events during reconnection) - // Skip in bot mode — Grammy handles dedup via update_id - if (this.bridge.getMode() !== "bot") { + // (GramJS may fire duplicate NewMessage events during reconnection). + if (this.bridge.requiresOffsetDedup()) { const postQueueOffset = readOffset(message.chatId) ?? 0; if (message.id <= postQueueOffset) { log.debug(`Skipping message ${message.id} (already processed after queue wait)`); @@ -473,7 +472,7 @@ export class MessageHandler { : message.text; const streamMode = this.fullConfig?.telegram?.stream_mode ?? "all"; const streamToChat = - this.bridge.getMode() === "bot" && this.bridge.streamResponse && streamMode !== "off" + this.bridge.streamResponse && streamMode !== "off" ? { chatId: message.chatId, bridge: this.bridge, @@ -573,9 +572,8 @@ export class MessageHandler { this.pendingHistory.clearPending(message.chatId); } - // Mark as processed AFTER successful handling (prevents message loss on crash) - // Skip in bot mode — Grammy handles dedup via update_id - if (this.bridge.getMode() !== "bot") { + // Mark as processed AFTER successful handling (prevents message loss on crash). + if (this.bridge.requiresOffsetDedup()) { writeOffset(message.id, message.chatId); } } finally { From f615dec6853e3f0fd888b558391c10877407af06 Mon Sep 17 00:00:00 2001 From: TONresistor Date: Fri, 29 May 2026 16:47:48 +0200 Subject: [PATCH 004/151] chore(deps): bump backend deps, TS 6, @hono/node-server 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - npm update in-range: hono, vitest, @vitest/coverage-v8, tsx, jscpd, @typescript-eslint/{eslint-plugin,parser} 8.60, @inquirer/prompts 8.5 - @ston-fi/api 0.31 -> 0.32 - @hono/node-server 1.19 -> 2.0.4 (drop Node18/Vercel, API serve inchangee) - typescript 5.9 -> 6.0.3 - tsconfig: retrait baseUrl/paths (alias @/ inutilise, 0 usage repo) ; ignoreDeprecations 6.0 sur les 2 tsconfig (tsup force baseUrl au build dts) Verifie: tsc ✓, eslint ✓, build (sdk+backend+web) ✓, knip ✓, dupcheck 4.9% ✓, madge ✓, 1588 tests ✓, npm audit --omit=dev 0 vuln, overrides axios/fast-xml-parser/xml-builder intacts. --- package-lock.json | 467 +++++++++++++++++++++---------------- package.json | 6 +- packages/sdk/tsconfig.json | 4 +- tsconfig.json | 7 +- 4 files changed, 276 insertions(+), 208 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c544e52..d6873809 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ ], "dependencies": { "@dedust/sdk": "^0.8.7", - "@hono/node-server": "^1.19.11", + "@hono/node-server": "^2.0.4", "@huggingface/transformers": "^3.8.1", "@inquirer/prompts": "^8.3.2", "@mariozechner/pi-ai": "^0.73.1", @@ -43,7 +43,7 @@ "teleton": "bin/teleton.js" }, "devDependencies": { - "@ston-fi/api": "^0.31.0", + "@ston-fi/api": "^0.32.0", "@ston-fi/sdk": "^2.7.0", "@types/better-sqlite3": "^7.6.13", "@types/node": "^22.0.0", @@ -60,7 +60,7 @@ "prettier": "^3.8.1", "tsup": "^8.5.1", "tsx": "^4.21.0", - "typescript": "^5.7.0", + "typescript": "^6.0.3", "vitest": "^4.1.1" }, "engines": { @@ -1213,12 +1213,12 @@ "license": "MIT" }, "node_modules/@hono/node-server": { - "version": "1.19.14", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", - "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.0.4.tgz", + "integrity": "sha512-Ut3y0dMMPWy6bZ2kVfx25EOVbZlm15dhF4mOsezMlhpNHy+4MkU1qN9Y6lnruYi4wPmFzimGX2X7LF/FwHli4A==", "license": "MIT", "engines": { - "node": ">=18.14.1" + "node": ">=20" }, "peerDependencies": { "hono": "^4" @@ -1777,24 +1777,24 @@ } }, "node_modules/@inquirer/ansi": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.5.tgz", - "integrity": "sha512-doc2sWgJpbFQ64UflSVd17ibMGDuxO1yKgOgLMwavzESnXjFWJqUeG8saYosqKpHp4kWiM5x1nXvEjbpx90gzw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.6.tgz", + "integrity": "sha512-I/INw4sHGlVZ/afZOckpLiDP9SmbMl1g/GCqeHjLw1Afw/0PlRs2tRFgTGWmdI0hoNuWZn3y2iHNmG1vyECyQQ==", "license": "MIT", "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" } }, "node_modules/@inquirer/checkbox": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.1.5.tgz", - "integrity": "sha512-Jmf9tgBHIEK5SAOB7swYfStqmtkZb00xOTpSQmkoGEpdxOTpJi9RS0A8bkfDPHTTItZRJrRdZrEMu25wyj0VfQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.0.tgz", + "integrity": "sha512-1HJt+3fqxblp/GQjdntSyoSHYBc0e3CzXVgjFpKA6qFLd9FHBBqwN8Co0xYH6t2JVUZrtFwZ4bBiwptkiLxyOg==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.5", - "@inquirer/core": "^11.1.10", - "@inquirer/figures": "^2.0.5", - "@inquirer/type": "^4.0.5" + "@inquirer/ansi": "^2.0.6", + "@inquirer/core": "^11.2.0", + "@inquirer/figures": "^2.0.6", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -1809,13 +1809,13 @@ } }, "node_modules/@inquirer/confirm": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.13.tgz", - "integrity": "sha512-wkGPC7yJ5WJk1DJ5SX7fzk+gfj4BM8cf5dDDi71B/551xHrdsZVRJOC0WyikXd0pEsb/9cLniuE4atbsMqmFkw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.0.tgz", + "integrity": "sha512-USpeB76eqK7yGricDlGAupxWlp4a59qpeZOoNWaxO/nJln7agpJveyNkQ1d5u8YXG6TOqxZtQpKPORQQDrdVsA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.10", - "@inquirer/type": "^4.0.5" + "@inquirer/core": "^11.2.0", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -1830,17 +1830,17 @@ } }, "node_modules/@inquirer/core": { - "version": "11.1.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.1.10.tgz", - "integrity": "sha512-a4Q5BXHQAHa9eO202sTaFCHFYVB3x5fauDuThEAdZ9gfn76pSxiKU7wWcEH0N1O0XmQvNfQNU6QXpiRxmYQx+A==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.0.tgz", + "integrity": "sha512-joR1YS2sI0us+9d0I8ViqFbrRLONO8CFTuyvBX4ZVBSch+VsZiugUABdrhBXXJR1VyEzvpz5SQCix3keETQ58g==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.5", - "@inquirer/figures": "^2.0.5", - "@inquirer/type": "^4.0.5", + "@inquirer/ansi": "^2.0.6", + "@inquirer/figures": "^2.0.6", + "@inquirer/type": "^4.0.6", "cli-width": "^4.1.0", "fast-wrap-ansi": "^0.2.0", - "mute-stream": "^3.0.0", + "mute-stream": "^4.0.0", "signal-exit": "^4.1.0" }, "engines": { @@ -1856,14 +1856,14 @@ } }, "node_modules/@inquirer/editor": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.1.2.tgz", - "integrity": "sha512-Y3Nor7S/DhIPo+8Ym/dSY4efwKI4BsflKDwXh0jNeXJsSF3dteS/3Yf+z4wkibVZDvYMyCgknSTQlNahfunGHg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.2.0.tgz", + "integrity": "sha512-/m+sgRmzSdK6HDtVnl3PmI6MnZC4O+LLezedoJcrX7mINhTjjb0hlC7aEDGZXkFTB4b5uQ0q59AhYTah88KbNg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.10", - "@inquirer/external-editor": "^3.0.0", - "@inquirer/type": "^4.0.5" + "@inquirer/core": "^11.2.0", + "@inquirer/external-editor": "^3.0.1", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -1878,13 +1878,13 @@ } }, "node_modules/@inquirer/expand": { - "version": "5.0.14", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.0.14.tgz", - "integrity": "sha512-qyY9zcIX2eKYwaAUiQo9zORd61Lc3sXeM72fVbeHkYnDkqfr8/armcRbmVAIrExeJhI2puk+uomeKtWrpUVUmQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.0.tgz", + "integrity": "sha512-fR7g4BVnIcs+4NApF6C5byflNM/EULxSxsv/2Jvg+gmop0R6eBIPvZqE6RYnTy1tQTFnf9wyHkwNoQSZbofaGA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.10", - "@inquirer/type": "^4.0.5" + "@inquirer/core": "^11.2.0", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -1899,9 +1899,9 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.0.tgz", - "integrity": "sha512-lDSwMgg+M5rq6JKBYaJwSX6T9e/HK2qqZ1oxmOwn4AQoJE5D+7TumsxLGC02PWS//rkIVqbZv3XA3ejsc9FYvg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.1.tgz", + "integrity": "sha512-tam+Gwjsxg2sx3iUVPkAnhKT/yrk2rd2NAa7XJU/J8OYpU0ifXsnp12xlvzp/DCpWBXVv+vLQsqnpAWwUcWD5Q==", "license": "MIT", "dependencies": { "chardet": "^2.1.1", @@ -1920,22 +1920,22 @@ } }, "node_modules/@inquirer/figures": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.5.tgz", - "integrity": "sha512-NsSs4kzfm12lNetHwAn3GEuH317IzpwrMCbOuMIVytpjnJ90YYHNwdRgYGuKmVxwuIqSgqk3M5qqQt1cDk0tGQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.6.tgz", + "integrity": "sha512-dsZgQtH2t5Q6ah3aPbZbeEZAxsD9qQu0DXf01AltuEfRTm+NoLN6+rLVbr+4edeEbNCp/wBNM6mALRWtsQpfkw==", "license": "MIT", "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" } }, "node_modules/@inquirer/input": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.13.tgz", - "integrity": "sha512-0l0jCHlJnXIV8CTxwQC0C+5Ziq8WP22edWgmciW2xYvoeoSck4v5FvCS1ctKdqLLR0dUo93uAHgWHywgBSoRyw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.0.tgz", + "integrity": "sha512-sVZCz6P6e8tW5g2bSFel1oLpa6jK/u7BexFfrgTqR8syIdnHqy+iopnlSbYBZMsCK52chLjhGNBxt0eRqhsghw==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.10", - "@inquirer/type": "^4.0.5" + "@inquirer/core": "^11.2.0", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -1950,13 +1950,13 @@ } }, "node_modules/@inquirer/number": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.0.13.tgz", - "integrity": "sha512-WHmkYnnJAou5gx7RgcvAfUggnHNM1zWfoh0dFPl3dxVssuqt+dK5rIbaOYQXNyOegvFnopbKupjnhw2O8gANNg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.1.0.tgz", + "integrity": "sha512-VMXB/XejCbaSTf9Xucl7dqjzzsaGsrs6XwSYXPbGZ2QbSuq/Gz8XamhSi9ClRubNXZlGry9xVg1tKkJdTDgCtQ==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.10", - "@inquirer/type": "^4.0.5" + "@inquirer/core": "^11.2.0", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -1971,14 +1971,14 @@ } }, "node_modules/@inquirer/password": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.0.13.tgz", - "integrity": "sha512-XDGu64ROHZjOOXLAANvJN7iIxWKhOSCG5VakrZ5kaScVR+snVJCFglD/hL3/677awtWcu4pXoWa280CDIYcBeg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.0.tgz", + "integrity": "sha512-5tqRuKCDIUxdPxTI/CuLnh914kz+WMPmURHKnZgui9gk43ebudEsdu4EwSn1CPSi5R+17YpBG+ba/YqTnRAcJA==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.5", - "@inquirer/core": "^11.1.10", - "@inquirer/type": "^4.0.5" + "@inquirer/ansi": "^2.0.6", + "@inquirer/core": "^11.2.0", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -1993,21 +1993,21 @@ } }, "node_modules/@inquirer/prompts": { - "version": "8.4.3", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.4.3.tgz", - "integrity": "sha512-ai5LseTw9HhegupIgmo4cn7RpnCGznjjXu4OI+7jMR8vu7T1ZCCNMzFFAovUCjL1fl0cceksIN1++yQE59SmZw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.5.0.tgz", + "integrity": "sha512-pLjXOnY4y3R1mgyHP3pXD/8eXejp+L/dde/0N2NLKgKfMstqhNZrpvs7Wkzbl9FYFQh10LRQ7QZwq+cz9rrhyw==", "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^5.1.5", - "@inquirer/confirm": "^6.0.13", - "@inquirer/editor": "^5.1.2", - "@inquirer/expand": "^5.0.14", - "@inquirer/input": "^5.0.13", - "@inquirer/number": "^4.0.13", - "@inquirer/password": "^5.0.13", - "@inquirer/rawlist": "^5.2.9", - "@inquirer/search": "^4.1.9", - "@inquirer/select": "^5.1.5" + "@inquirer/checkbox": "^5.2.0", + "@inquirer/confirm": "^6.1.0", + "@inquirer/editor": "^5.2.0", + "@inquirer/expand": "^5.1.0", + "@inquirer/input": "^5.1.0", + "@inquirer/number": "^4.1.0", + "@inquirer/password": "^5.1.0", + "@inquirer/rawlist": "^5.3.0", + "@inquirer/search": "^4.2.0", + "@inquirer/select": "^5.2.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -2022,13 +2022,13 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "5.2.9", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.2.9.tgz", - "integrity": "sha512-a1ErXEfgjfPYpyQ89dp+7n2IISjH9oQg3ygvF5adz8B7aHn4n2PjEgu1wpVTp69K3bj3lVLxP0qJ2b1clk1Whw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.0.tgz", + "integrity": "sha512-p+vAeTAD+cGXjGleP1F5LXrX2ISxNDZm+lqeBpnJausNLSZskZZkcggwhomqP8Igx9oIjnoeOrw98xvdFvdm2w==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.10", - "@inquirer/type": "^4.0.5" + "@inquirer/core": "^11.2.0", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -2043,14 +2043,14 @@ } }, "node_modules/@inquirer/search": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.1.9.tgz", - "integrity": "sha512-ZlbM28Q9lmLkFPNAIv+ZuY530n5Km8U1WW48oYEvDhe9yc2uL3m3t+JSdRUkQlk5fuIuskgiIVjcb7czFzQpuA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.2.0.tgz", + "integrity": "sha512-ByURoSGIaSl5O5Q0AmYmVmUsXbMUcBGNoA3FRL7TOyiA22IeFHymJKRkuILbOIlJwqnBk7AnPpseodyFUBzg+g==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.10", - "@inquirer/figures": "^2.0.5", - "@inquirer/type": "^4.0.5" + "@inquirer/core": "^11.2.0", + "@inquirer/figures": "^2.0.6", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -2065,15 +2065,15 @@ } }, "node_modules/@inquirer/select": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.1.5.tgz", - "integrity": "sha512-6SRg6kHfK/sjLXOsuqNebuir+sjwrf/iWuRUnXgB2slzEewppI1WfzeS16XxDcOQmXBruMmmB9Cgrz7wsAxqMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.0.tgz", + "integrity": "sha512-6IzkcmEbEXfgVbxZ2d1UyJFbCBoc6dTofulFmrYuomIp88HXiVqRbqbg4/mbfZhvnNo6xYmnYo2AEmDof6fQkg==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.5", - "@inquirer/core": "^11.1.10", - "@inquirer/figures": "^2.0.5", - "@inquirer/type": "^4.0.5" + "@inquirer/ansi": "^2.0.6", + "@inquirer/core": "^11.2.0", + "@inquirer/figures": "^2.0.6", + "@inquirer/type": "^4.0.6" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -2088,9 +2088,9 @@ } }, "node_modules/@inquirer/type": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.5.tgz", - "integrity": "sha512-aetVUNeKNc/VriqXlw1NRSW0zhMBB0W4bNbWRJgzRl/3d0QNDQFfk0GO5SDdtjMZVg6o8ZKEiadd7SCCzoOn5Q==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.6.tgz", + "integrity": "sha512-J+9tdxOskuYuGjsvGaq00AamhDgjR7anhEW2dP4QdQpFCMPngCeC/bCYWQ5NsMWZRdsy53is7kAHb/+7cwDk2g==", "license": "MIT", "engines": { "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" @@ -2156,9 +2156,9 @@ } }, "node_modules/@jscpd/badge-reporter": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@jscpd/badge-reporter/-/badge-reporter-4.2.3.tgz", - "integrity": "sha512-yNvbwWl/NwogHT5XrHyqXgF9yVZeLWA2QOhGqYTopvgi7LsSbDumpOqOcJMHP9Z4RalhMfahh+dVXFSI7tMcaA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@jscpd/badge-reporter/-/badge-reporter-4.2.4.tgz", + "integrity": "sha512-g5vu05u0lX9rcHA0k3CptLfpOiuMzxh5+mUe2iYRAznTwH3ks6JAVAf9aPi5mBFttMCRiJh2zSt3xnSadHtMGg==", "dev": true, "license": "MIT", "dependencies": { @@ -2168,9 +2168,9 @@ } }, "node_modules/@jscpd/core": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@jscpd/core/-/core-4.2.3.tgz", - "integrity": "sha512-VQ2gH+tiI51ty3PBRD4HClNNgyX/VH9cs0dcFKuywxDzLQ64jYp7vhJPcqnyiVX9tVEIAa12sucRHQP/VHwugA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@jscpd/core/-/core-4.2.4.tgz", + "integrity": "sha512-9V9YzmmhYg9682kFqi+n0KGOhXNSoqxHbuIP3i/l/oSd6upBOnnSeBWDZMGOenQRQnyKEtCIbnS9YFz+3B+siQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2178,14 +2178,14 @@ } }, "node_modules/@jscpd/finder": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@jscpd/finder/-/finder-4.2.3.tgz", - "integrity": "sha512-ZpjviFAg6zLojQHS+owvrn8DG1OY1d4835Je4LUKzbMurndmQDhvRRFDkN9V6xPn6gvRaMVkJHN2tyljsnUjWA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@jscpd/finder/-/finder-4.2.4.tgz", + "integrity": "sha512-4LLEuAAmAraud/TAAlB5BByVdWfy7SYiPKacj5yEggpkNs0qsw2kiZ5EyU3LonB+/vntJJEDDpJMmvOeS58e0A==", "dev": true, "license": "MIT", "dependencies": { - "@jscpd/core": "4.2.3", - "@jscpd/tokenizer": "4.2.3", + "@jscpd/core": "4.2.4", + "@jscpd/tokenizer": "4.2.4", "blamer": "^1.0.6", "bytes": "^3.1.2", "cli-table3": "^0.6.5", @@ -2197,9 +2197,9 @@ } }, "node_modules/@jscpd/html-reporter": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@jscpd/html-reporter/-/html-reporter-4.2.3.tgz", - "integrity": "sha512-kp1pqJXCKwyRu5mJK5IvXdFQEDHWQDb7svLFlbVXGI0dVH1y1XNl8mrIrSoRw+0AySxhDkuSyIlQOSDC2GRwQg==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@jscpd/html-reporter/-/html-reporter-4.2.4.tgz", + "integrity": "sha512-6UljCTVGf7O+o6D6fs1zNBG+vR1PTn47W2mSgb5hzSrvNw60rLrVoAMZMnr/TeIEdd/OEgAu+icbdvvVBfnvJw==", "dev": true, "license": "MIT", "dependencies": { @@ -2209,13 +2209,13 @@ } }, "node_modules/@jscpd/tokenizer": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@jscpd/tokenizer/-/tokenizer-4.2.3.tgz", - "integrity": "sha512-RvjD7/hwqtcQC9MWOl31odTti6kGCFxZ77DKEhwyMn+r6oVEUFbXgcGvzn0GC/wuTl7f3j5MF9JNMeTneOFwYA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@jscpd/tokenizer/-/tokenizer-4.2.4.tgz", + "integrity": "sha512-nM4kGyDvpcevt8t0zOsMQ82ShSc65c3LIQUHClTYwraiOGOmWgUQyen+JIiFCNF8eDCGR2Qa5iI5XBfGWYQzIg==", "dev": true, "license": "MIT", "dependencies": { - "@jscpd/core": "4.2.3", + "@jscpd/core": "4.2.4", "spark-md5": "^3.0.2" } }, @@ -2296,6 +2296,18 @@ } } }, + "node_modules/@modelcontextprotocol/sdk/node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", @@ -3644,11 +3656,10 @@ "license": "MIT" }, "node_modules/@ston-fi/api": { - "version": "0.31.0", - "resolved": "https://registry.npmjs.org/@ston-fi/api/-/api-0.31.0.tgz", - "integrity": "sha512-ct06MzR8Sk7GkMMleGO3G651Kyv15KKuHlm5xYgzIPCLe8s6f0gXVQW1yRvpHwNOwbkyIdx4m1k+9V+8abTojQ==", + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@ston-fi/api/-/api-0.32.0.tgz", + "integrity": "sha512-1Z9++yFaDQIDaoIX5Vz+LnqFe+Wzaq6P65TW38KTqOyymvztvHj7yLI1bMGDoFB3EjZ8HPR4z2LUMstyrBT0dQ==", "dev": true, - "hasInstallScript": true, "license": "MIT", "dependencies": { "camelcase-keys": "9.1.3", @@ -3967,17 +3978,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.3.tgz", - "integrity": "sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.0.tgz", + "integrity": "sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/type-utils": "8.59.3", - "@typescript-eslint/utils": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/type-utils": "8.60.0", + "@typescript-eslint/utils": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -3990,22 +4001,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.59.3", + "@typescript-eslint/parser": "^8.60.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.3.tgz", - "integrity": "sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.0.tgz", + "integrity": "sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", "debug": "^4.4.3" }, "engines": { @@ -4021,14 +4032,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.3.tgz", - "integrity": "sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.0.tgz", + "integrity": "sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.59.3", - "@typescript-eslint/types": "^8.59.3", + "@typescript-eslint/tsconfig-utils": "^8.60.0", + "@typescript-eslint/types": "^8.60.0", "debug": "^4.4.3" }, "engines": { @@ -4043,14 +4054,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.3.tgz", - "integrity": "sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.0.tgz", + "integrity": "sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3" + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4061,9 +4072,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.3.tgz", - "integrity": "sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.0.tgz", + "integrity": "sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==", "dev": true, "license": "MIT", "engines": { @@ -4078,15 +4089,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.3.tgz", - "integrity": "sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.0.tgz", + "integrity": "sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3", - "@typescript-eslint/utils": "8.59.3", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/utils": "8.60.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -4103,9 +4114,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.3.tgz", - "integrity": "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.0.tgz", + "integrity": "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==", "dev": true, "license": "MIT", "engines": { @@ -4117,16 +4128,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.3.tgz", - "integrity": "sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.0.tgz", + "integrity": "sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.59.3", - "@typescript-eslint/tsconfig-utils": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", + "@typescript-eslint/project-service": "8.60.0", + "@typescript-eslint/tsconfig-utils": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -4145,16 +4156,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.3.tgz", - "integrity": "sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.0.tgz", + "integrity": "sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3" + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4169,13 +4180,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz", - "integrity": "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.0.tgz", + "integrity": "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.59.3", + "@typescript-eslint/types": "8.60.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -5708,6 +5719,20 @@ "node": ">=18" } }, + "node_modules/dependency-tree/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/destr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", @@ -6772,9 +6797,9 @@ "license": "BSD-3-Clause" }, "node_modules/fast-wrap-ansi": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.0.tgz", - "integrity": "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", "license": "MIT", "dependencies": { "fast-string-width": "^3.0.2" @@ -6933,6 +6958,20 @@ "node": ">=18" } }, + "node_modules/filing-cabinet/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -7544,9 +7583,9 @@ "license": "MIT" }, "node_modules/hono": { - "version": "4.12.19", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.19.tgz", - "integrity": "sha512-xa3eYXYXx68XTT4hZ7dRzsXBhaq85ToSrlUJNoR0gwz/1Ap/CNwX47wfvV7pc/xWhjKVVkLT7zBJy8chhNguqQ==", + "version": "4.12.23", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", + "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -8054,30 +8093,30 @@ "license": "MIT" }, "node_modules/jscpd": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/jscpd/-/jscpd-4.2.3.tgz", - "integrity": "sha512-/1BEga1E1cY56/sdQOzU/PFtnea+n1beqG8/Xx4HopG9c5rkUO8ptnu9En8Xf1ILGW6KSWidV4vLQTm2FGYvpw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/jscpd/-/jscpd-4.2.4.tgz", + "integrity": "sha512-PSo2U0G8OxULayGyQMv7T/0ZQ+c3PPltdMOz/57v9Xnmq5xSIhh4cnZ0oYZPKqejy10aFwAbMVxqAlo24+PQ3g==", "dev": true, "license": "MIT", "dependencies": { - "@jscpd/badge-reporter": "4.2.3", - "@jscpd/core": "4.2.3", - "@jscpd/finder": "4.2.3", - "@jscpd/html-reporter": "4.2.3", - "@jscpd/tokenizer": "4.2.3", + "@jscpd/badge-reporter": "4.2.4", + "@jscpd/core": "4.2.4", + "@jscpd/finder": "4.2.4", + "@jscpd/html-reporter": "4.2.4", + "@jscpd/tokenizer": "4.2.4", "colors": "^1.4.0", "commander": "^5.0.0", "fs-extra": "^11.2.0", - "jscpd-sarif-reporter": "4.2.3" + "jscpd-sarif-reporter": "4.2.4" }, "bin": { "jscpd": "bin/jscpd" } }, "node_modules/jscpd-sarif-reporter": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/jscpd-sarif-reporter/-/jscpd-sarif-reporter-4.2.3.tgz", - "integrity": "sha512-rM0LM5S0kdASLCtDsr1s51rJOPf8nubaxaWQUTWVVPda1UMPymXbELG+A3Rgpoa4D4QFUFfXqz60Jn/W+vlFtA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/jscpd-sarif-reporter/-/jscpd-sarif-reporter-4.2.4.tgz", + "integrity": "sha512-JtX79kFSyAhqJh5TdLUcvtYJtJd1F8UW8b4Miaga+EIgUn2/nR0N2zWL9mH5cRXgbzLuQbbsw9kReUVIECApwQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9290,12 +9329,12 @@ "license": "MIT" }, "node_modules/mute-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", - "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-4.0.0.tgz", + "integrity": "sha512-gSrprq0fJ3EiOErzjdIZrjysVVmJ4uu1QWfCDss5LypA5OXvrMje5Ym5z6V6RLyJ2eF87lasX7t6a0AnFvZblg==", "license": "ISC", "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" } }, "node_modules/mz": { @@ -10226,6 +10265,20 @@ "node": ">=18" } }, + "node_modules/precinct/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -12351,9 +12404,9 @@ "license": "MIT" }, "node_modules/tsx": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.1.tgz", - "integrity": "sha512-TvncJykhxAzFCk0VQZKBTClall4Pm7qXDSodb6uxi8QFa8X8mT6ABjxxsQ2opDRYxG7AzcRWXaFtruz5HJKuWg==", + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.3.tgz", + "integrity": "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==", "dev": true, "license": "MIT", "dependencies": { @@ -12975,9 +13028,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -13632,6 +13685,20 @@ "optional": true } } + }, + "packages/sdk/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } } } } diff --git a/package.json b/package.json index db33bea3..03126bc4 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ }, "dependencies": { "@dedust/sdk": "^0.8.7", - "@hono/node-server": "^1.19.11", + "@hono/node-server": "^2.0.4", "@huggingface/transformers": "^3.8.1", "@inquirer/prompts": "^8.3.2", "@mariozechner/pi-ai": "^0.73.1", @@ -96,7 +96,7 @@ "axios": ">=1.15.2" }, "devDependencies": { - "@ston-fi/api": "^0.31.0", + "@ston-fi/api": "^0.32.0", "@ston-fi/sdk": "^2.7.0", "@types/better-sqlite3": "^7.6.13", "@types/node": "^22.0.0", @@ -113,7 +113,7 @@ "prettier": "^3.8.1", "tsup": "^8.5.1", "tsx": "^4.21.0", - "typescript": "^5.7.0", + "typescript": "^6.0.3", "vitest": "^4.1.1" }, "engines": { diff --git a/packages/sdk/tsconfig.json b/packages/sdk/tsconfig.json index c4c21d43..9d47fe42 100644 --- a/packages/sdk/tsconfig.json +++ b/packages/sdk/tsconfig.json @@ -10,7 +10,9 @@ "rootDir": "src", "declaration": true, "declarationMap": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + // tsup force baseUrl pendant le build dts (rollup.js) — deprecie en TS6. Silence jusqu'au support TS7 de tsup. + "ignoreDeprecations": "6.0" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] diff --git a/tsconfig.json b/tsconfig.json index de4affce..18cdf135 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,10 +12,9 @@ "resolveJsonModule": true, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, - "baseUrl": ".", - "paths": { - "@/*": ["src/*"] - } + // tsup force baseUrl pendant le build dts (rollup.js) — deprecie en TS6. + // Silence jusqu'a ce que tsup gere TS7. A retirer quand tsup n'injecte plus baseUrl. + "ignoreDeprecations": "6.0" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "src/**/__tests__"] From 89438c8a72c1b51a7ce43ec59d56c5e2371aebf1 Mon Sep 17 00:00:00 2001 From: TONresistor Date: Fri, 29 May 2026 16:53:40 +0200 Subject: [PATCH 005/151] chore(deps): add knip 6, defer TS 6 (dev toolchain not ready) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit knip 5 -> 6.14.2 (dev-only): $schema -> knip@6, drop now-redundant ignoreDependencies (pino-pretty, @teleton-agent/sdk) per knip6 hints. Installing knip 6 surfaced a latent peer conflict introduced by f615dec: madge@8 (latest) declares peerOptional typescript@^5.4.4, incompatible with TS 6 — every future npm install would then need --legacy-peer-deps. TS 6 also forced ignoreDeprecations:6.0 (tsup injects a deprecated baseUrl at the dts build). TS 6 brings no functional gain here (tsconfig already strict). => revert typescript to ^5.7.0 (5.9.3), drop ignoreDeprecations. The baseUrl/paths cleanup from f615dec is kept (alias @/ unused, 0 usage). Verifie: tsc 5.9 OK, eslint OK, build (sdk+backend+web) OK, knip6 clean, dupcheck 4.9%, madge no cycle. --- knip.json | 4 +- package-lock.json | 504 +++++++++++++++++++++++++++++++------ package.json | 4 +- packages/sdk/tsconfig.json | 4 +- tsconfig.json | 5 +- 5 files changed, 429 insertions(+), 92 deletions(-) diff --git a/knip.json b/knip.json index 0658b5fa..cc4af4a3 100644 --- a/knip.json +++ b/knip.json @@ -1,5 +1,5 @@ { - "$schema": "https://unpkg.com/knip@5/schema.json", + "$schema": "https://unpkg.com/knip@6/schema.json", "workspaces": { ".": { "entry": [ @@ -19,8 +19,6 @@ } }, "ignoreDependencies": [ - "pino-pretty", - "@teleton-agent/sdk", "@grammyjs/types" ], "ignoreExportsUsedInFile": true, diff --git a/package-lock.json b/package-lock.json index d6873809..21165f17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,13 +54,13 @@ "eslint": "^10.1.0", "husky": "^9.1.7", "jscpd": "^4.0.8", - "knip": "^5.85.0", + "knip": "^6.14.2", "lint-staged": "^16.4.0", "madge": "^8.0.0", "prettier": "^3.8.1", "tsup": "^8.5.1", "tsx": "^4.21.0", - "typescript": "^6.0.3", + "typescript": "^5.9.3", "vitest": "^4.1.1" }, "engines": { @@ -2389,6 +2389,348 @@ "node": ">= 8" } }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.130.0.tgz", + "integrity": "sha512-h/xYU8/7ADWzVSf5I+YalLpj33LOy9CI/zgbJNIZ5eunRBG+Czqa3lZsvuPHHf3rOt6z1c5+UzoxjbAzAvhwVw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.130.0.tgz", + "integrity": "sha512-oFWFJrsGv9siFM4HjMqKNB7IuIZD/SMmZdCXl8xyx7lDplGvPKyewpOo272rSWgMXe2Wx7bWI0Yj+gkHv4qbeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.130.0.tgz", + "integrity": "sha512-sGUzupdTplK9jQg7eJZ878HfEgQjJNBc6dAYVWJ9W5aU+J8rLfRJhTVsKThiu1pNwm6Y1qKCcbC6WhNWSXR3Ig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.130.0.tgz", + "integrity": "sha512-PsB4cdCISbC00Uy8eiD8bc2AkGWjZqrSrJnkBFuG2ptrrf6mZ2F5gLFSjOAVMMgZPg8B1D7OydJwLWSfyI2Plg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.130.0.tgz", + "integrity": "sha512-DgABp3l38hS77JbXCV4qk1+n6DPym5u8zzwuweokezm2tX194nDSJDENbDRECxVsiNbprKATLbk+Z5wlHT0OHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.130.0.tgz", + "integrity": "sha512-4Kn3CTEmwFrzhTSC/JuUW16qovmaMdX7jeSKbL8w0pLtLww7To1a2XJi9Z5uD8QWUkfUHhqfV+VD6dVzBnWzoA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.130.0.tgz", + "integrity": "sha512-D35KZM3F4rRu1uAFKyBlg3Gaf/ybCjyaPR1hfgvk5ex8NtcTmRgc0JgSighEyNg96TPrFhemFba68SZuxaha8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.130.0.tgz", + "integrity": "sha512-Q9o7oVlo955KHwS8l1u0bCzIx+JsZUA3XToLXC+MsMhye/9LeBQbt84nh120cl2XLy+TEzvugYDiHShg5yaX6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.130.0.tgz", + "integrity": "sha512-EiJ/gC0ljbcwVpycC8YWw6ggMbtsPX8XMOt0mPx0aqWeMsNR+L9m05Flbvd5T+GlivG+GkSWQL7tM9SRFpM/dw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.130.0.tgz", + "integrity": "sha512-b+h/lsLLurp756dMGizNs5uPaJfyEdWrTcV5t8M609jWm1DEHB1StpRXCkyvwtkJx3m+qL5BNQ0dEKan/4yGFA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.130.0.tgz", + "integrity": "sha512-O19Cil83XAyjEFfo8WhkMwY58ALqZ7ckjGL+25mjMIuF84urWBeANH0FC8B8BsSSygWU3/1aY3ADdDbp+wlBnw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.130.0.tgz", + "integrity": "sha512-BgXRVC0+83n3YzCscLQjj6nbyeBIVeZYPTI4fFMAE4WNm2+4RXhWp03IVizL7esIz36kgmT48aebk1iM+cs8sw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.130.0.tgz", + "integrity": "sha512-6tJz0xvnGhsokE7N1WlUSBXibpYmT9xSJFS1Ce41Km/+8gQvdlW8MLhRv8PD0L7ix8vRG0FDDepp3jdOFzdVdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.130.0.tgz", + "integrity": "sha512-9aCWj83dp3heTQGmGnZGdIWgxjZrr/7VQ0TGFHH5PKByxJKF2Hcr4qvaSUHhhGEa3MSsDjTL1YDP8RAgdL5/Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.130.0.tgz", + "integrity": "sha512-afXt87aZBqrUVli8TB/I8H1G50RDWcwirjWtXGXYqJ2ZqWEiErH7V72j3LUSDZaivmtu2OLX0KQ/mbhP81mr7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.130.0.tgz", + "integrity": "sha512-I0NCrZV/YZuCGWgqwNN/GO/iXlLF2z+Wgc7u+Aa9N4P51oYeIa0XT+zVBUne4csO9GqxskXgI4g8JzzWGRpfOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.130.0.tgz", + "integrity": "sha512-sJgQkGaBX0WJvPUDfwciex6IcTk5O5NLQ1bhEb6f3nBruh1GshKMRSMt2bxZlYrgBzjyBbJzsnO+InPG0bg+fA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.130.0.tgz", + "integrity": "sha512-bjcma99sQrNh6RY4mPO9yTkfxql6TDFoN3HWdK31RCKXwNhcDgJXW/l8PUtzKNiQ+9vpKJfJtQq+LklBuxSOBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.130.0.tgz", + "integrity": "sha512-hRYbv6HhpSTzT4xTiIkadLI7upLQxuOdLPR/9nL1fTjwhgutBTPXrwaAPb/jTFVx6/8C7Jb5HcUKhmNwloTbFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.130.0.tgz", + "integrity": "sha512-RBpA9TsRucJq6HNVNCFF1iKg+QeTkLdZf7hi4xaOGCPvMZWvDHjQgSOEZMUpuW4JNciHbxNhLEYmz5CVygjVGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-project/types": { "version": "0.130.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz", @@ -5719,20 +6061,6 @@ "node": ">=18" } }, - "node_modules/dependency-tree/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/destr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", @@ -6958,20 +7286,6 @@ "node": ">=18" } }, - "node_modules/filing-cabinet/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -7368,6 +7682,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/get-uri": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", @@ -8294,9 +8621,9 @@ } }, "node_modules/knip": { - "version": "5.88.1", - "resolved": "https://registry.npmjs.org/knip/-/knip-5.88.1.tgz", - "integrity": "sha512-tpy5o7zu1MjawVkLPuahymVJekYY3kYjvzcoInhIchgePxTlo+api90tBv2KfhAIe5uXh+mez1tAfmbv8/TiZg==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/knip/-/knip-6.14.2.tgz", + "integrity": "sha512-Vg3JhIINjZew1I7qAFI4UHemW1mc4azP/BxJvsq9eGDfxpGO7oVCuD/bsWkog9TO/ZwwJeAeOMFZ1kd9jnY9+Q==", "dev": true, "funding": [ { @@ -8310,18 +8637,19 @@ ], "license": "ISC", "dependencies": { - "@nodelib/fs.walk": "^1.2.3", - "fast-glob": "^3.3.3", + "fdir": "^6.5.0", "formatly": "^0.3.0", - "jiti": "^2.6.0", + "get-tsconfig": "4.14.0", + "jiti": "^2.7.0", "minimist": "^1.2.8", + "oxc-parser": "^0.130.0", "oxc-resolver": "^11.19.1", - "picocolors": "^1.1.1", - "picomatch": "^4.0.1", - "smol-toml": "^1.5.2", + "picomatch": "^4.0.4", + "smol-toml": "^1.6.1", "strip-json-comments": "5.0.3", - "unbash": "^2.2.0", - "yaml": "^2.8.2", + "tinyglobby": "^0.2.16", + "unbash": "^3.0.0", + "yaml": "^2.9.0", "zod": "^4.1.11" }, "bin": { @@ -8329,11 +8657,7 @@ "knip-bun": "bin/knip-bun.js" }, "engines": { - "node": ">=18.18.0" - }, - "peerDependencies": { - "@types/node": ">=18", - "typescript": ">=5.0.4 <7" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/levn": { @@ -9746,6 +10070,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/oxc-parser": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.130.0.tgz", + "integrity": "sha512-X0PJ+NmOok8qP3vK9uaW431ngkdM9UPEK7KG466urtIL2+EYTEgbZK2yqe2MWKJKBjRlFweP/pJPx0x9muMEVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.130.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.130.0", + "@oxc-parser/binding-android-arm64": "0.130.0", + "@oxc-parser/binding-darwin-arm64": "0.130.0", + "@oxc-parser/binding-darwin-x64": "0.130.0", + "@oxc-parser/binding-freebsd-x64": "0.130.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.130.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.130.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.130.0", + "@oxc-parser/binding-linux-arm64-musl": "0.130.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.130.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.130.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.130.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.130.0", + "@oxc-parser/binding-linux-x64-gnu": "0.130.0", + "@oxc-parser/binding-linux-x64-musl": "0.130.0", + "@oxc-parser/binding-openharmony-arm64": "0.130.0", + "@oxc-parser/binding-wasm32-wasi": "0.130.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.130.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.130.0", + "@oxc-parser/binding-win32-x64-msvc": "0.130.0" + } + }, "node_modules/oxc-resolver": { "version": "11.19.1", "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.19.1.tgz", @@ -10265,20 +10627,6 @@ "node": ">=18" } }, - "node_modules/precinct/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -10859,6 +11207,16 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", @@ -13028,9 +13386,9 @@ } }, "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -13049,9 +13407,9 @@ "license": "MIT" }, "node_modules/unbash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unbash/-/unbash-2.2.0.tgz", - "integrity": "sha512-X2wH19RAPZE3+ldGicOkoj/SIA83OIxcJ6Cuaw23hf8Xc6fQpvZXY0SftE2JgS0QhYLUG4uwodSI3R53keyh7w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unbash/-/unbash-3.0.0.tgz", + "integrity": "sha512-FeFPZ/WFT0mbRCuydiZzpPFlrYN8ZUpphQKoq4EeElVIYjYyGzPMxQR/simUwCOJIyVhpFk4RbtyO7RuMpMnHA==", "dev": true, "license": "ISC", "engines": { @@ -13685,20 +14043,6 @@ "optional": true } } - }, - "packages/sdk/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } } } } diff --git a/package.json b/package.json index 03126bc4..4f3d3f42 100644 --- a/package.json +++ b/package.json @@ -107,13 +107,13 @@ "eslint": "^10.1.0", "husky": "^9.1.7", "jscpd": "^4.0.8", - "knip": "^5.85.0", + "knip": "^6.14.2", "lint-staged": "^16.4.0", "madge": "^8.0.0", "prettier": "^3.8.1", "tsup": "^8.5.1", "tsx": "^4.21.0", - "typescript": "^6.0.3", + "typescript": "^5.9.3", "vitest": "^4.1.1" }, "engines": { diff --git a/packages/sdk/tsconfig.json b/packages/sdk/tsconfig.json index 9d47fe42..c4c21d43 100644 --- a/packages/sdk/tsconfig.json +++ b/packages/sdk/tsconfig.json @@ -10,9 +10,7 @@ "rootDir": "src", "declaration": true, "declarationMap": true, - "forceConsistentCasingInFileNames": true, - // tsup force baseUrl pendant le build dts (rollup.js) — deprecie en TS6. Silence jusqu'au support TS7 de tsup. - "ignoreDeprecations": "6.0" + "forceConsistentCasingInFileNames": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] diff --git a/tsconfig.json b/tsconfig.json index 18cdf135..c093043d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,10 +11,7 @@ "declaration": true, "resolveJsonModule": true, "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - // tsup force baseUrl pendant le build dts (rollup.js) — deprecie en TS6. - // Silence jusqu'a ce que tsup gere TS7. A retirer quand tsup n'injecte plus baseUrl. - "ignoreDeprecations": "6.0" + "forceConsistentCasingInFileNames": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "src/**/__tests__"] From 51f4f12493eccb7617289416342de292f9582b0b Mon Sep 17 00:00:00 2001 From: TONresistor Date: Fri, 29 May 2026 17:00:01 +0200 Subject: [PATCH 006/151] chore(models): dual pricing $IN/$OUT, fix Opus 4.7 label, add 2 models - prix dual $IN/$OUT (verifies registre pi-ai 0.73.1) sur anthropic/ openai/google/xai ; ex Opus $5/$25, Sonnet $3/$15, Gemini 2.5 Pro $1.25/$10 - label Opus 4.7 'Most capable' -> 'Most capable available' (4.8 hors pi-ai) - ajout gemini-3.1-flash-lite-preview ($0.25/$1.50, 1M) + grok-4-1-fast-non-reasoning ($0.20/$0.50, 2M) - consomme via getModelsForProvider() -> remonte auto dans WebUI + onboard ; schema.model = z.string() libre, IDs valides Verifie: tsc, eslint, prettier, build backend. --- src/config/model-catalog.ts | 54 +++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/src/config/model-catalog.ts b/src/config/model-catalog.ts index 8c53cfd8..3989fadc 100644 --- a/src/config/model-catalog.ts +++ b/src/config/model-catalog.ts @@ -15,54 +15,54 @@ export const MODEL_OPTIONS: Record = { { value: "claude-opus-4-7", name: "Claude Opus 4.7", - description: "Most capable, 1M ctx, reasoning, $5/M", + description: "Most capable available, 1M ctx, reasoning, $5/$25", }, { value: "claude-opus-4-6", name: "Claude Opus 4.6", - description: "Previous gen, 1M ctx, reasoning, $5/M", + description: "Previous gen, 1M ctx, reasoning, $5/$25", }, { value: "claude-opus-4-5-20251101", name: "Claude Opus 4.5", - description: "Older gen, 200K ctx, $5/M", + description: "Older gen, 200K ctx, $5/$25", }, { value: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", - description: "Balanced, 1M ctx, reasoning, $3/M", + description: "Balanced, 1M ctx, reasoning, $3/$15", }, { value: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5", - description: "Fast & cheap, 200K ctx, $1/M (default)", + description: "Fast & cheap, 200K ctx, $1/$5 (default)", }, ], openai: [ { value: "gpt-5.5", name: "GPT-5.5", - description: "Latest frontier, reasoning, 272K ctx, $5/M", + description: "Latest frontier, reasoning, 272K ctx, $5/$30", }, { value: "gpt-5.5-pro", name: "GPT-5.5 Pro", - description: "Max capability, reasoning, 1M ctx, $30/M", + description: "Max capability, reasoning, 1M ctx, $30/$180", }, - { value: "gpt-5.4", name: "GPT-5.4", description: "Reasoning, 272K ctx, $2.50/M" }, + { value: "gpt-5.4", name: "GPT-5.4", description: "Reasoning, 272K ctx, $2.50/$15" }, { value: "gpt-5.4-pro", name: "GPT-5.4 Pro", - description: "Extended thinking, 1M ctx, $30/M", + description: "Extended thinking, 1M ctx, $30/$180", }, { value: "gpt-5.4-mini", name: "GPT-5.4 Mini", - description: "Fast & cheap, reasoning, 400K ctx, $0.75/M", + description: "Fast & cheap, reasoning, 400K ctx, $0.75/$4.50", }, - { value: "gpt-4o", name: "GPT-4o", description: "Balanced, 128K ctx, $2.50/M" }, - { value: "gpt-4.1", name: "GPT-4.1", description: "1M ctx, $2/M" }, - { value: "gpt-4.1-mini", name: "GPT-4.1 Mini", description: "1M ctx, cheap, $0.40/M" }, + { value: "gpt-4o", name: "GPT-4o", description: "Balanced, 128K ctx, $2.50/$10" }, + { value: "gpt-4.1", name: "GPT-4.1", description: "1M ctx, $2/$8" }, + { value: "gpt-4.1-mini", name: "GPT-4.1 Mini", description: "1M ctx, cheap, $0.40/$1.60" }, ], "openai-codex": [ { value: "gpt-5.5", name: "GPT-5.5", description: "Latest frontier, reasoning, 272K ctx" }, @@ -79,31 +79,45 @@ export const MODEL_OPTIONS: Record = { { value: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro", - description: "Preview, latest gen, reasoning, 1M ctx", + description: "Preview, latest gen, reasoning, 1M ctx, $2/$12", + }, + { + value: "gemini-3.1-flash-lite-preview", + name: "Gemini 3.1 Flash Lite", + description: "Preview, fast & cheap, reasoning, 1M ctx, $0.25/$1.50", + }, + { value: "gemini-2.5-pro", name: "Gemini 2.5 Pro", description: "Stable, 1M ctx, $1.25/$10" }, + { + value: "gemini-2.5-flash", + name: "Gemini 2.5 Flash", + description: "Fast, 1M ctx, $0.30/$2.50", }, - { value: "gemini-2.5-pro", name: "Gemini 2.5 Pro", description: "Stable, 1M ctx, $1.25/M" }, - { value: "gemini-2.5-flash", name: "Gemini 2.5 Flash", description: "Fast, 1M ctx, $0.30/M" }, { value: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash Lite", - description: "Ultra cheap, 1M ctx, $0.10/M", + description: "Ultra cheap, 1M ctx, $0.10/$0.40", }, ], xai: [ { value: "grok-4.3", name: "Grok 4.3", - description: "Latest, reasoning, vision, 1M ctx, $1.25/M", + description: "Latest, reasoning, vision, 1M ctx, $1.25/$2.50", }, { value: "grok-4.20-0309-reasoning", name: "Grok 4.20 Reasoning", - description: "Reasoning, vision, 2M ctx, $2/M", + description: "Reasoning, vision, 2M ctx, $2/$6", }, { value: "grok-4.20-0309-non-reasoning", name: "Grok 4.20 Non-Reasoning", - description: "Fast, vision, 2M ctx, $2/M", + description: "Fast, vision, 2M ctx, $2/$6", + }, + { + value: "grok-4-1-fast-non-reasoning", + name: "Grok 4.1 Fast", + description: "Fast, vision, 2M ctx, $0.20/$0.50", }, ], groq: [ From 2d537a86ae027048f1120246a947f7af9c722324 Mon Sep 17 00:00:00 2001 From: TONresistor Date: Fri, 29 May 2026 17:05:20 +0200 Subject: [PATCH 007/151] fix(tools,agent): drop dead schema params, fix gift ToolResult, retries dont burn iterations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pin.ts: remove silent/both_sides (never passed to bridge.pinMessage) - send-dice.ts: remove reply_to (bridge.sendDice ignores it, SDK drops as _replyToId) - gift bot-tools: wrap return in data:{} (runtime serializes result.data only — total/gifts were invisible to the LLM) + category data-bearing (sibling parity) - runtime loop: LLM retries (overflow/rate-limit/server) decrement iteration so transient errors no longer consume the productive max_agentic_iterations budget (still bounded by RATE_LIMIT/SERVER_ERROR_MAX_RETRIES) Verifie: tsc, eslint, build backend, 1588 tests. --- src/agent/runtime.ts | 3 ++ .../telegram/gifts/get-available-gifts-bot.ts | 27 ++++++++------ .../tools/telegram/gifts/get-user-gifts.ts | 37 +++++++++++-------- .../tools/telegram/interactive/send-dice.ts | 6 --- src/agent/tools/telegram/messaging/pin.ts | 12 ------ 5 files changed, 40 insertions(+), 45 deletions(-) diff --git a/src/agent/runtime.ts b/src/agent/runtime.ts index 89e6ae6f..bcfd50f9 100644 --- a/src/agent/runtime.ts +++ b/src/agent/runtime.ts @@ -852,6 +852,7 @@ export class AgentRuntime { appendToTranscript(session.sessionId, userMsg); log.info(`Retrying with fresh context...`); + iteration--; // recovery retry, not a productive iteration — don't consume the budget continue; } else if (errorMsg.toLowerCase().includes("rate") || errorMsg.includes("429")) { rateLimitRetries++; @@ -861,6 +862,7 @@ export class AgentRuntime { `Rate limited, retrying in ${delay}ms (attempt ${rateLimitRetries}/${RATE_LIMIT_MAX_RETRIES})...` ); await new Promise((r) => setTimeout(r, delay)); + iteration--; // transient retry, not a productive iteration — don't consume the budget continue; } log.error(`Rate limited after ${RATE_LIMIT_MAX_RETRIES} retries: ${errorMsg}`); @@ -883,6 +885,7 @@ export class AgentRuntime { `Server error, retrying in ${delay}ms (attempt ${serverErrorRetries}/${SERVER_ERROR_MAX_RETRIES})...` ); await new Promise((r) => setTimeout(r, delay)); + iteration--; // transient retry, not a productive iteration — don't consume the budget continue; } log.error(`Server error after ${SERVER_ERROR_MAX_RETRIES} retries: ${errorMsg}`); diff --git a/src/agent/tools/telegram/gifts/get-available-gifts-bot.ts b/src/agent/tools/telegram/gifts/get-available-gifts-bot.ts index 24fbf7d1..2b6c4da3 100644 --- a/src/agent/tools/telegram/gifts/get-available-gifts-bot.ts +++ b/src/agent/tools/telegram/gifts/get-available-gifts-bot.ts @@ -1,10 +1,11 @@ import { Type } from "@sinclair/typebox"; -import type { ToolEntry } from "../../types.js"; +import type { Tool, ToolEntry } from "../../types.js"; -const tool = { +const tool: Tool = { name: "telegram_get_available_gifts_bot", description: "List sendable Star Gifts via the Bot API (requires bot_token). Returns gift ID, Stars cost, upgrade cost, and remaining stock. For the userbot catalog (with resale/collectible info), use telegram_get_available_gifts instead.", + category: "data-bearing", parameters: Type.Object({}), }; @@ -43,16 +44,18 @@ const executor = async (_params: any, context: any) => { const gifts = data.result?.gifts ?? []; return { success: true, - total: gifts.length, - gifts: gifts.map((g) => ({ - id: g.id, - star_count: g.star_count, - upgrade_star_count: g.upgrade_star_count ?? null, - total_count: g.total_count ?? null, - remaining_count: g.remaining_count ?? null, - premium_only: g.is_premium || false, - emoji: g.sticker?.emoji ?? null, - })), + data: { + total: gifts.length, + gifts: gifts.map((g) => ({ + id: g.id, + star_count: g.star_count, + upgrade_star_count: g.upgrade_star_count ?? null, + total_count: g.total_count ?? null, + remaining_count: g.remaining_count ?? null, + premium_only: g.is_premium || false, + emoji: g.sticker?.emoji ?? null, + })), + }, }; }; diff --git a/src/agent/tools/telegram/gifts/get-user-gifts.ts b/src/agent/tools/telegram/gifts/get-user-gifts.ts index fc675682..d42c2857 100644 --- a/src/agent/tools/telegram/gifts/get-user-gifts.ts +++ b/src/agent/tools/telegram/gifts/get-user-gifts.ts @@ -1,10 +1,11 @@ import { Type } from "@sinclair/typebox"; -import type { ToolEntry } from "../../types.js"; +import type { Tool, ToolEntry } from "../../types.js"; -const tool = { +const tool: Tool = { name: "telegram_get_user_gifts", description: "Get gifts publicly displayed on a user's Telegram profile via Bot API (requires bot_token). Only returns gifts the user has chosen to show. For the full received-gifts inventory including private ones, use telegram_get_my_gifts.", + category: "data-bearing", parameters: Type.Object({ user_id: Type.Number({ description: "Telegram user ID to look up" }), }), @@ -47,19 +48,25 @@ const executor = async (params: any, context: any) => { const result = data.result ?? { total_count: 0, gifts: [] }; return { success: true, - total: result.total_count, - gifts: result.gifts.map((g) => ({ - type: g.type, - gift_id: g.gift?.id, - star_count: g.gift?.star_count, - sender: g.sender_user - ? { id: g.sender_user.id, name: g.sender_user.first_name, username: g.sender_user.username } - : null, - date: g.send_date, - text: g.text || null, - private: g.is_private || false, - convert_stars: g.convert_star_count, - })), + data: { + total: result.total_count, + gifts: result.gifts.map((g) => ({ + type: g.type, + gift_id: g.gift?.id, + star_count: g.gift?.star_count, + sender: g.sender_user + ? { + id: g.sender_user.id, + name: g.sender_user.first_name, + username: g.sender_user.username, + } + : null, + date: g.send_date, + text: g.text || null, + private: g.is_private || false, + convert_stars: g.convert_star_count, + })), + }, }; }; diff --git a/src/agent/tools/telegram/interactive/send-dice.ts b/src/agent/tools/telegram/interactive/send-dice.ts index 1cbe1eb3..9493ba26 100644 --- a/src/agent/tools/telegram/interactive/send-dice.ts +++ b/src/agent/tools/telegram/interactive/send-dice.ts @@ -12,7 +12,6 @@ const log = createLogger("Tools"); interface SendDiceParams { chat_id: string; emoticon?: "🎲" | "🎯" | "🏀" | "⚽" | "🎰" | "🎳"; - reply_to?: number; } export const telegramSendDiceTool: Tool = { @@ -29,11 +28,6 @@ export const telegramSendDiceTool: Tool = { enum: ["🎲", "🎯", "🏀", "⚽", "🎰", "🎳"], }) ), - reply_to: Type.Optional( - Type.Number({ - description: "Message ID to reply to", - }) - ), }), }; diff --git a/src/agent/tools/telegram/messaging/pin.ts b/src/agent/tools/telegram/messaging/pin.ts index 89c0e6c7..8ee0748b 100644 --- a/src/agent/tools/telegram/messaging/pin.ts +++ b/src/agent/tools/telegram/messaging/pin.ts @@ -15,8 +15,6 @@ const log = createLogger("Tools"); interface PinMessageParams { chat_id: string; message_id: number; - silent?: boolean; - both_sides?: boolean; } export const telegramPinMessageTool: Tool = { @@ -29,16 +27,6 @@ export const telegramPinMessageTool: Tool = { message_id: Type.Number({ description: "ID of the message to pin", }), - silent: Type.Optional( - Type.Boolean({ - description: "Pin silently without notification (default: false)", - }) - ), - both_sides: Type.Optional( - Type.Boolean({ - description: "Pin for both sides in private chats (default: true)", - }) - ), }), }; From a625adee9df86b4aab339bb08ebbf69ca8d91c74 Mon Sep 17 00:00:00 2001 From: TONresistor Date: Fri, 29 May 2026 17:09:35 +0200 Subject: [PATCH 008/151] fix(webui): React.Fragment key in Tools, shared SearchInput in Memory/Conversations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tools.tsx: anonymous <> with keys on children -> on the mapped root (fixes React key warning); drop now-redundant inner tr keys - SearchInput: optional wrapperStyle prop (backward-compatible) - Memory/Conversations: replace raw flex filter inputs with shared SearchInput (adds clear button + Escape-to-clear, consolidates duplicated markup) Verifie: tsc --noEmit -p web/tsconfig.json (mes 4 fichiers OK), build:web. Note: 8 erreurs de type WebUI PRE-EXISTANTES non liees (AgentControl, Config, Dashboard, Setup, setup/*) — blind-spot #1, a traiter separement. --- web/src/components/SearchInput.tsx | 5 +++-- web/src/pages/Conversations.tsx | 9 +++++---- web/src/pages/Memory.tsx | 9 +++++---- web/src/pages/Tools.tsx | 9 ++++----- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/web/src/components/SearchInput.tsx b/web/src/components/SearchInput.tsx index fb3562a0..bb9581b4 100644 --- a/web/src/components/SearchInput.tsx +++ b/web/src/components/SearchInput.tsx @@ -3,11 +3,12 @@ interface SearchInputProps { onChange: (value: string) => void; placeholder?: string; style?: React.CSSProperties; + wrapperStyle?: React.CSSProperties; } -export function SearchInput({ value, onChange, placeholder = 'Search...', style }: SearchInputProps) { +export function SearchInput({ value, onChange, placeholder = 'Search...', style, wrapperStyle }: SearchInputProps) { return ( -
+
{/* Search + refresh bar */}
- setFilter(e.target.value)} + onChange={setFilter} placeholder="Filter chats..." - style={{ flex: 1, padding: '6px 10px', fontSize: '13px' }} + wrapperStyle={{ flex: 1 }} + style={{ width: '100%' }} /> )} - diff --git a/web/src/pages/Workspace.tsx b/web/src/pages/Workspace.tsx index 66d8e63c..3177c4fe 100644 --- a/web/src/pages/Workspace.tsx +++ b/web/src/pages/Workspace.tsx @@ -361,6 +361,7 @@ export function Workspace() { e.stopPropagation()}>