@poolzin/pool-bot 2026.2.0 → 2026.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +9 -11
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/model-selection.js +21 -0
- package/dist/agents/pi-embedded-block-chunker.js +117 -42
- package/dist/agents/pi-embedded-helpers/errors.js +183 -78
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +1 -0
- package/dist/agents/pi-embedded-runner/model.js +61 -2
- package/dist/agents/pi-embedded-runner/run/attempt.js +21 -11
- package/dist/agents/pi-embedded-runner/run.js +199 -46
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-tools.js +10 -5
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- package/dist/agents/shell-utils.js +51 -0
- package/dist/agents/skills/bundled-context.js +23 -0
- package/dist/agents/skills/bundled-dir.js +41 -7
- package/dist/agents/skills-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +24 -0
- package/dist/agents/tools/cron-tool.js +166 -19
- package/dist/agents/tools/discord-actions-presence.js +78 -0
- package/dist/agents/tools/message-tool.js +56 -2
- package/dist/agents/tools/sessions-history-tool.js +69 -1
- package/dist/agents/tools/web-search.js +211 -42
- package/dist/agents/usage.js +23 -1
- package/dist/agents/workspace-run.js +67 -0
- package/dist/agents/workspace-templates.js +44 -0
- package/dist/auto-reply/command-auth.js +121 -6
- package/dist/auto-reply/envelope.js +50 -72
- package/dist/auto-reply/reply/commands-compact.js +1 -0
- package/dist/auto-reply/reply/commands-context-report.js +1 -0
- package/dist/auto-reply/reply/commands-context.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +107 -60
- package/dist/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/reply/get-reply-run.js +2 -1
- package/dist/auto-reply/reply/inbound-context.js +5 -1
- package/dist/auto-reply/reply/model-selection.js +3 -3
- package/dist/auto-reply/thinking.js +88 -43
- package/dist/browser/bridge-server.js +13 -0
- package/dist/browser/cdp.helpers.js +38 -24
- package/dist/browser/client-fetch.js +50 -7
- package/dist/browser/config.js +1 -10
- package/dist/browser/extension-relay.js +101 -40
- package/dist/browser/pw-ai.js +1 -1
- package/dist/browser/pw-session.js +143 -8
- package/dist/browser/pw-tools-core.interactions.js +125 -27
- package/dist/browser/pw-tools-core.responses.js +1 -1
- package/dist/browser/pw-tools-core.state.js +1 -1
- package/dist/browser/routes/agent.act.js +86 -41
- package/dist/browser/routes/dispatcher.js +4 -4
- package/dist/browser/screenshot.js +1 -1
- package/dist/browser/server.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/reply-prefix.js +8 -1
- package/dist/cli/cron-cli/register.cron-add.js +61 -40
- package/dist/cli/cron-cli/register.cron-edit.js +60 -34
- package/dist/cli/cron-cli/shared.js +56 -41
- package/dist/cli/dns-cli.js +26 -14
- package/dist/cli/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +5 -5
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/update-cli.js +173 -52
- package/dist/commands/agent.js +1 -0
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-state-migrations.js +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/model-allowlist.js +29 -0
- package/dist/commands/model-picker.js +2 -1
- package/dist/commands/models/list.status-command.js +43 -23
- package/dist/commands/models/shared.js +15 -0
- package/dist/commands/onboard-custom.js +384 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +6 -3
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/config/defaults.js +3 -2
- package/dist/config/paths.js +136 -35
- package/dist/config/plugin-auto-enable.js +21 -5
- package/dist/config/redact-snapshot.js +153 -0
- package/dist/config/schema.field-metadata.js +590 -0
- package/dist/config/schema.js +2 -2
- package/dist/config/sessions/store.js +291 -23
- package/dist/config/zod-schema.agent-defaults.js +3 -0
- package/dist/config/zod-schema.agent-runtime.js +13 -2
- package/dist/config/zod-schema.providers-core.js +142 -0
- package/dist/config/zod-schema.session.js +3 -0
- package/dist/cron/delivery.js +57 -0
- package/dist/cron/isolated-agent/delivery-target.js +18 -3
- package/dist/cron/isolated-agent/helpers.js +22 -5
- package/dist/cron/isolated-agent/run.js +171 -63
- package/dist/cron/isolated-agent/session.js +2 -0
- package/dist/cron/normalize.js +356 -28
- package/dist/cron/parse.js +10 -5
- package/dist/cron/run-log.js +35 -10
- package/dist/cron/schedule.js +41 -6
- package/dist/cron/service/jobs.js +208 -35
- package/dist/cron/service/ops.js +72 -16
- package/dist/cron/service/state.js +2 -0
- package/dist/cron/service/store.js +386 -14
- package/dist/cron/service/timer.js +390 -147
- package/dist/cron/session-reaper.js +86 -0
- package/dist/cron/store.js +23 -8
- package/dist/cron/validate-timestamp.js +43 -0
- package/dist/discord/monitor/agent-components.js +438 -0
- package/dist/discord/monitor/allow-list.js +28 -5
- package/dist/discord/monitor/gateway-registry.js +29 -0
- package/dist/discord/monitor/native-command.js +44 -23
- package/dist/discord/monitor/sender-identity.js +45 -0
- package/dist/discord/pluralkit.js +27 -0
- package/dist/discord/send.outbound.js +92 -5
- package/dist/discord/send.shared.js +60 -23
- package/dist/discord/targets.js +84 -1
- package/dist/entry.js +15 -9
- package/dist/extensionAPI.js +8 -0
- package/dist/gateway/control-ui.js +8 -1
- package/dist/gateway/hooks-mapping.js +3 -0
- package/dist/gateway/hooks.js +65 -0
- package/dist/gateway/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- package/dist/gateway/origin-check.js +56 -0
- package/dist/gateway/protocol/client-info.js +9 -0
- package/dist/gateway/protocol/index.js +9 -2
- package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
- package/dist/gateway/protocol/schema/cron.js +22 -10
- package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
- package/dist/gateway/protocol/schema/sessions.js +12 -0
- package/dist/gateway/server/hooks.js +1 -1
- package/dist/gateway/server-broadcast.js +26 -9
- package/dist/gateway/server-chat.js +112 -23
- package/dist/gateway/server-discovery-runtime.js +10 -2
- package/dist/gateway/server-http.js +109 -11
- package/dist/gateway/server-methods/agent-timestamp.js +60 -0
- package/dist/gateway/server-methods/agents.js +321 -2
- package/dist/gateway/server-methods/usage.js +559 -16
- package/dist/gateway/server-runtime-state.js +22 -8
- package/dist/gateway/server-startup-memory.js +16 -0
- package/dist/gateway/server.impl.js +5 -1
- package/dist/gateway/session-utils.fs.js +23 -25
- package/dist/gateway/session-utils.js +20 -10
- package/dist/gateway/sessions-patch.js +7 -22
- package/dist/gateway/test-helpers.server.js +35 -2
- package/dist/imessage/constants.js +2 -0
- package/dist/imessage/monitor/deliver.js +4 -1
- package/dist/imessage/monitor/monitor-provider.js +51 -1
- package/dist/infra/bonjour-discovery.js +131 -70
- package/dist/infra/control-ui-assets.js +134 -12
- package/dist/infra/errors.js +12 -0
- package/dist/infra/exec-approvals.js +266 -57
- package/dist/infra/format-time/format-datetime.js +79 -0
- package/dist/infra/format-time/format-duration.js +81 -0
- package/dist/infra/format-time/format-relative.js +80 -0
- package/dist/infra/heartbeat-runner.js +140 -49
- package/dist/infra/home-dir.js +54 -0
- package/dist/infra/net/fetch-guard.js +122 -0
- package/dist/infra/net/ssrf.js +65 -29
- package/dist/infra/outbound/abort.js +14 -0
- package/dist/infra/outbound/message-action-runner.js +77 -13
- package/dist/infra/outbound/outbound-session.js +143 -37
- package/dist/infra/poolbot-root.js +43 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- package/dist/infra/update-global.js +35 -0
- package/dist/infra/update-runner.js +149 -43
- package/dist/infra/warning-filter.js +65 -0
- package/dist/infra/widearea-dns.js +30 -9
- package/dist/logging/redact-identifier.js +12 -0
- package/dist/media/fetch.js +81 -58
- package/dist/media-understanding/apply.js +403 -3
- package/dist/media-understanding/attachments.js +38 -27
- package/dist/media-understanding/defaults.js +16 -0
- package/dist/media-understanding/providers/deepgram/audio.js +22 -14
- package/dist/media-understanding/providers/google/audio.js +24 -17
- package/dist/media-understanding/providers/google/video.js +24 -17
- package/dist/media-understanding/providers/image.js +2 -2
- package/dist/media-understanding/providers/index.js +4 -1
- package/dist/media-understanding/providers/openai/audio.js +22 -14
- package/dist/media-understanding/providers/shared.js +16 -11
- package/dist/media-understanding/providers/zai/index.js +6 -0
- package/dist/media-understanding/runner.js +158 -90
- package/dist/memory/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +28 -16
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +154 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/node-host/runner.js +34 -24
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/source-display.js +51 -0
- package/dist/process/exec.js +20 -2
- package/dist/routing/resolve-route.js +12 -0
- package/dist/routing/session-key.js +15 -0
- package/dist/runtime.js +2 -0
- package/dist/security/audit-extra.async.js +601 -0
- package/dist/security/audit-extra.js +2 -830
- package/dist/security/audit-extra.sync.js +505 -0
- package/dist/security/channel-metadata.js +34 -0
- package/dist/security/external-content.js +88 -6
- package/dist/security/skill-scanner.js +330 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +1 -2
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +37 -10
- package/dist/telegram/bot-message-dispatch.js +48 -15
- package/dist/telegram/bot-native-commands.js +86 -29
- package/dist/telegram/bot.js +30 -29
- package/dist/telegram/model-buttons.js +163 -0
- package/dist/telegram/monitor.js +110 -85
- package/dist/telegram/send.js +129 -47
- package/dist/terminal/restore.js +45 -0
- package/dist/test-helpers/state-dir-env.js +16 -0
- package/dist/tts/tts.js +12 -6
- package/dist/tui/tui-session-actions.js +166 -54
- package/dist/utils/fetch-timeout.js +20 -0
- package/dist/utils/normalize-secret-input.js +19 -0
- package/dist/utils/transcript-tools.js +58 -0
- package/dist/utils.js +45 -14
- package/dist/version.js +42 -5
- package/package.json +1 -1
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { resolveEffectiveMessagesConfig } from "../agents/identity.js";
|
|
2
1
|
import { resolveChunkMode } from "../auto-reply/chunk.js";
|
|
3
2
|
import { buildCommandTextFromArgs, findCommandByNativeName, listNativeCommandSpecs, listNativeCommandSpecsForConfig, parseCommandArgs, resolveCommandArgMenu, } from "../auto-reply/commands-registry.js";
|
|
4
|
-
import { listSkillCommandsForAgents } from "../auto-reply/skill-commands.js";
|
|
5
|
-
import { resolveTelegramCustomCommands } from "../config/telegram-custom-commands.js";
|
|
6
|
-
import { dispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.js";
|
|
7
3
|
import { finalizeInboundContext } from "../auto-reply/reply/inbound-context.js";
|
|
8
|
-
import {
|
|
4
|
+
import { dispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.js";
|
|
5
|
+
import { listSkillCommandsForAgents } from "../auto-reply/skill-commands.js";
|
|
6
|
+
import { resolveCommandAuthorizedFromAuthorizers } from "../channels/command-gating.js";
|
|
7
|
+
import { createReplyPrefixContext } from "../channels/reply-prefix.js";
|
|
9
8
|
import { resolveMarkdownTableMode } from "../config/markdown-tables.js";
|
|
10
|
-
import {
|
|
9
|
+
import { resolveTelegramCustomCommands } from "../config/telegram-custom-commands.js";
|
|
11
10
|
import { normalizeTelegramCommandName, TELEGRAM_COMMAND_NAME_PATTERN, } from "../config/telegram-custom-commands.js";
|
|
11
|
+
import { danger, logVerbose } from "../globals.js";
|
|
12
|
+
import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
|
|
13
|
+
import { executePluginCommand, getPluginCommandSpecs, matchPluginCommand, } from "../plugins/commands.js";
|
|
12
14
|
import { resolveAgentRoute } from "../routing/resolve-route.js";
|
|
13
15
|
import { resolveThreadSessionKeys } from "../routing/session-key.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
+
import { withTelegramApiErrorLogging } from "./api-logging.js";
|
|
17
|
+
import { firstDefined, isSenderAllowed, normalizeAllowFromWithStore } from "./bot-access.js";
|
|
16
18
|
import { deliverReplies } from "./bot/delivery.js";
|
|
19
|
+
import { buildTelegramThreadParams, buildSenderName, buildTelegramGroupFrom, buildTelegramGroupPeerId, resolveTelegramForumThreadId, } from "./bot/helpers.js";
|
|
17
20
|
import { buildInlineKeyboard } from "./send.js";
|
|
18
|
-
import { buildSenderName, buildTelegramGroupFrom, buildTelegramGroupPeerId, resolveTelegramForumThreadId, } from "./bot/helpers.js";
|
|
19
|
-
import { firstDefined, isSenderAllowed, normalizeAllowFromWithStore } from "./bot-access.js";
|
|
20
|
-
import { readTelegramAllowFromStore } from "./pairing-store.js";
|
|
21
21
|
async function resolveTelegramCommandAuth(params) {
|
|
22
22
|
const { msg, bot, cfg, telegramCfg, allowFrom, groupAllowFrom, useAccessGroups, resolveGroupPolicy, resolveTelegramGroupConfig, requireAuth, } = params;
|
|
23
23
|
const chatId = msg.chat.id;
|
|
@@ -28,7 +28,7 @@ async function resolveTelegramCommandAuth(params) {
|
|
|
28
28
|
isForum,
|
|
29
29
|
messageThreadId,
|
|
30
30
|
});
|
|
31
|
-
const storeAllowFrom = await
|
|
31
|
+
const storeAllowFrom = await readChannelAllowFromStore("telegram").catch(() => []);
|
|
32
32
|
const { groupConfig, topicConfig } = resolveTelegramGroupConfig(chatId, resolvedThreadId);
|
|
33
33
|
const groupAllowOverride = firstDefined(topicConfig?.allowFrom, groupConfig?.allowFrom);
|
|
34
34
|
const effectiveGroupAllow = normalizeAllowFromWithStore({
|
|
@@ -69,7 +69,7 @@ async function resolveTelegramCommandAuth(params) {
|
|
|
69
69
|
}
|
|
70
70
|
if (isGroup && useAccessGroups) {
|
|
71
71
|
const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
|
|
72
|
-
const groupPolicy = telegramCfg.groupPolicy
|
|
72
|
+
const groupPolicy = firstDefined(topicConfig?.groupPolicy, groupConfig?.groupPolicy, telegramCfg.groupPolicy, defaultGroupPolicy, "open");
|
|
73
73
|
if (groupPolicy === "disabled") {
|
|
74
74
|
await withTelegramApiErrorLogging({
|
|
75
75
|
operation: "sendMessage",
|
|
@@ -134,7 +134,13 @@ async function resolveTelegramCommandAuth(params) {
|
|
|
134
134
|
};
|
|
135
135
|
}
|
|
136
136
|
export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, telegramCfg, allowFrom, groupAllowFrom, replyToMode, textLimit, useAccessGroups, nativeEnabled, nativeSkillsEnabled, nativeDisabledExplicit, resolveGroupPolicy, resolveTelegramGroupConfig, shouldSkipUpdate, opts, }) => {
|
|
137
|
-
const
|
|
137
|
+
const boundRoute = nativeEnabled && nativeSkillsEnabled
|
|
138
|
+
? resolveAgentRoute({ cfg, channel: "telegram", accountId })
|
|
139
|
+
: null;
|
|
140
|
+
const boundAgentIds = boundRoute && boundRoute.matchedBy.startsWith("binding.") ? [boundRoute.agentId] : null;
|
|
141
|
+
const skillCommands = nativeEnabled && nativeSkillsEnabled
|
|
142
|
+
? listSkillCommandsForAgents(boundAgentIds ? { cfg, agentIds: boundAgentIds } : { cfg })
|
|
143
|
+
: [];
|
|
138
144
|
const nativeCommands = nativeEnabled
|
|
139
145
|
? listNativeCommandSpecsForConfig(cfg, { skillCommands, provider: "telegram" })
|
|
140
146
|
: [];
|
|
@@ -180,7 +186,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
180
186
|
existingCommands.add(normalized);
|
|
181
187
|
pluginCommands.push({ command: normalized, description });
|
|
182
188
|
}
|
|
183
|
-
const
|
|
189
|
+
const allCommandsFull = [
|
|
184
190
|
...nativeCommands.map((command) => ({
|
|
185
191
|
command: command.name,
|
|
186
192
|
description: command.description,
|
|
@@ -188,12 +194,39 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
188
194
|
...pluginCommands,
|
|
189
195
|
...customCommands,
|
|
190
196
|
];
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
197
|
+
// Telegram Bot API limits commands to 100 per scope.
|
|
198
|
+
// Truncate with a warning rather than failing with BOT_COMMANDS_TOO_MUCH.
|
|
199
|
+
const TELEGRAM_MAX_COMMANDS = 100;
|
|
200
|
+
if (allCommandsFull.length > TELEGRAM_MAX_COMMANDS) {
|
|
201
|
+
runtime.log?.(`telegram: truncating ${allCommandsFull.length} commands to ${TELEGRAM_MAX_COMMANDS} (Telegram Bot API limit)`);
|
|
202
|
+
}
|
|
203
|
+
const allCommands = allCommandsFull.slice(0, TELEGRAM_MAX_COMMANDS);
|
|
204
|
+
// Clear stale commands before registering new ones to prevent
|
|
205
|
+
// leftover commands from deleted skills persisting across restarts.
|
|
206
|
+
// Chain delete → set so a late-resolving delete cannot wipe newly registered commands.
|
|
207
|
+
const registerCommands = () => {
|
|
208
|
+
if (allCommands.length > 0) {
|
|
209
|
+
withTelegramApiErrorLogging({
|
|
210
|
+
operation: "setMyCommands",
|
|
211
|
+
runtime,
|
|
212
|
+
fn: () => bot.api.setMyCommands(allCommands),
|
|
213
|
+
}).catch(() => { });
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
if (typeof bot.api.deleteMyCommands === "function") {
|
|
217
|
+
withTelegramApiErrorLogging({
|
|
218
|
+
operation: "deleteMyCommands",
|
|
194
219
|
runtime,
|
|
195
|
-
fn: () => bot.api.
|
|
196
|
-
})
|
|
220
|
+
fn: () => bot.api.deleteMyCommands(),
|
|
221
|
+
})
|
|
222
|
+
.catch(() => { })
|
|
223
|
+
.then(registerCommands)
|
|
224
|
+
.catch(() => { });
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
registerCommands();
|
|
228
|
+
}
|
|
229
|
+
if (allCommands.length > 0) {
|
|
197
230
|
if (typeof bot.command !== "function") {
|
|
198
231
|
logVerbose("telegram: bot.command unavailable; skipping native handlers");
|
|
199
232
|
}
|
|
@@ -201,10 +234,12 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
201
234
|
for (const command of nativeCommands) {
|
|
202
235
|
bot.command(command.name, async (ctx) => {
|
|
203
236
|
const msg = ctx.message;
|
|
204
|
-
if (!msg)
|
|
237
|
+
if (!msg) {
|
|
205
238
|
return;
|
|
206
|
-
|
|
239
|
+
}
|
|
240
|
+
if (shouldSkipUpdate(ctx)) {
|
|
207
241
|
return;
|
|
242
|
+
}
|
|
208
243
|
const auth = await resolveTelegramCommandAuth({
|
|
209
244
|
msg,
|
|
210
245
|
bot,
|
|
@@ -217,9 +252,12 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
217
252
|
resolveTelegramGroupConfig,
|
|
218
253
|
requireAuth: true,
|
|
219
254
|
});
|
|
220
|
-
if (!auth)
|
|
255
|
+
if (!auth) {
|
|
221
256
|
return;
|
|
257
|
+
}
|
|
222
258
|
const { chatId, isGroup, isForum, resolvedThreadId, senderId, senderUsername, groupConfig, topicConfig, commandAuthorized, } = auth;
|
|
259
|
+
const messageThreadId = msg.message_thread_id;
|
|
260
|
+
const threadParams = buildTelegramThreadParams(resolvedThreadId) ?? {};
|
|
223
261
|
const commandDefinition = findCommandByNativeName(command.name, "telegram");
|
|
224
262
|
const rawText = ctx.match?.trim() ?? "";
|
|
225
263
|
const commandArgs = commandDefinition
|
|
@@ -261,7 +299,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
261
299
|
runtime,
|
|
262
300
|
fn: () => bot.api.sendMessage(chatId, title, {
|
|
263
301
|
...(replyMarkup ? { reply_markup: replyMarkup } : {}),
|
|
264
|
-
...
|
|
302
|
+
...threadParams,
|
|
265
303
|
}),
|
|
266
304
|
});
|
|
267
305
|
return;
|
|
@@ -276,9 +314,13 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
276
314
|
},
|
|
277
315
|
});
|
|
278
316
|
const baseSessionKey = route.sessionKey;
|
|
279
|
-
|
|
317
|
+
// DMs: use raw messageThreadId for thread sessions (not resolvedThreadId which is for forums)
|
|
318
|
+
const dmThreadId = !isGroup ? messageThreadId : undefined;
|
|
280
319
|
const threadKeys = dmThreadId != null
|
|
281
|
-
? resolveThreadSessionKeys({
|
|
320
|
+
? resolveThreadSessionKeys({
|
|
321
|
+
baseSessionKey,
|
|
322
|
+
threadId: String(dmThreadId),
|
|
323
|
+
})
|
|
282
324
|
: null;
|
|
283
325
|
const sessionKey = threadKeys?.sessionKey ?? baseSessionKey;
|
|
284
326
|
const tableMode = resolveMarkdownTableMode({
|
|
@@ -299,6 +341,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
299
341
|
: (buildSenderName(msg) ?? String(senderId || chatId));
|
|
300
342
|
const ctxPayload = finalizeInboundContext({
|
|
301
343
|
Body: prompt,
|
|
344
|
+
BodyForAgent: prompt,
|
|
302
345
|
RawBody: prompt,
|
|
303
346
|
CommandBody: prompt,
|
|
304
347
|
CommandArgs: commandArgs,
|
|
@@ -318,6 +361,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
318
361
|
CommandAuthorized: commandAuthorized,
|
|
319
362
|
CommandSource: "native",
|
|
320
363
|
SessionKey: `telegram:slash:${senderId || chatId}`,
|
|
364
|
+
AccountId: route.accountId,
|
|
321
365
|
CommandTargetSessionKey: sessionKey,
|
|
322
366
|
MessageThreadId: resolvedThreadId,
|
|
323
367
|
IsForum: isForum,
|
|
@@ -329,12 +373,16 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
329
373
|
? !telegramCfg.blockStreaming
|
|
330
374
|
: undefined;
|
|
331
375
|
const chunkMode = resolveChunkMode(cfg, "telegram", route.accountId);
|
|
376
|
+
const { onModelSelected, ...prefixOptions } = createReplyPrefixContext({
|
|
377
|
+
cfg,
|
|
378
|
+
agentId: route.agentId,
|
|
379
|
+
});
|
|
332
380
|
await dispatchReplyWithBufferedBlockDispatcher({
|
|
333
381
|
ctx: ctxPayload,
|
|
334
382
|
cfg,
|
|
335
383
|
dispatcherOptions: {
|
|
336
|
-
|
|
337
|
-
deliver: async (payload) => {
|
|
384
|
+
...prefixOptions,
|
|
385
|
+
deliver: async (payload, _info) => {
|
|
338
386
|
await deliverReplies({
|
|
339
387
|
replies: [payload],
|
|
340
388
|
chatId: String(chatId),
|
|
@@ -356,6 +404,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
356
404
|
replyOptions: {
|
|
357
405
|
skillFilter,
|
|
358
406
|
disableBlockStreaming,
|
|
407
|
+
onModelSelected,
|
|
359
408
|
},
|
|
360
409
|
});
|
|
361
410
|
});
|
|
@@ -393,7 +442,11 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
393
442
|
});
|
|
394
443
|
if (!auth)
|
|
395
444
|
return;
|
|
396
|
-
const { resolvedThreadId, senderId, commandAuthorized } = auth;
|
|
445
|
+
const { resolvedThreadId, senderId, commandAuthorized, isGroup } = auth;
|
|
446
|
+
const from = isGroup
|
|
447
|
+
? buildTelegramGroupFrom(chatId, resolvedThreadId)
|
|
448
|
+
: `telegram:${chatId}`;
|
|
449
|
+
const to = `telegram:${chatId}`;
|
|
397
450
|
const result = await executePluginCommand({
|
|
398
451
|
command: match.command,
|
|
399
452
|
args: match.args,
|
|
@@ -402,6 +455,10 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
|
|
|
402
455
|
isAuthorizedSender: commandAuthorized,
|
|
403
456
|
commandBody,
|
|
404
457
|
config: cfg,
|
|
458
|
+
from,
|
|
459
|
+
to,
|
|
460
|
+
accountId,
|
|
461
|
+
messageThreadId: resolvedThreadId,
|
|
405
462
|
});
|
|
406
463
|
const tableMode = resolveMarkdownTableMode({
|
|
407
464
|
cfg,
|
package/dist/telegram/bot.js
CHANGED
|
@@ -17,9 +17,8 @@ import { enqueueSystemEvent } from "../infra/system-events.js";
|
|
|
17
17
|
import { getChildLogger } from "../logging.js";
|
|
18
18
|
import { withTelegramApiErrorLogging } from "./api-logging.js";
|
|
19
19
|
import { resolveAgentRoute } from "../routing/resolve-route.js";
|
|
20
|
-
import { resolveThreadSessionKeys } from "../routing/session-key.js";
|
|
21
20
|
import { resolveTelegramAccount } from "./accounts.js";
|
|
22
|
-
import { buildTelegramGroupPeerId, resolveTelegramForumThreadId, resolveTelegramStreamMode, } from "./bot/helpers.js";
|
|
21
|
+
import { buildTelegramGroupPeerId, buildTelegramParentPeer, resolveTelegramForumThreadId, resolveTelegramStreamMode, } from "./bot/helpers.js";
|
|
23
22
|
import { registerTelegramHandlers } from "./bot-handlers.js";
|
|
24
23
|
import { createTelegramMessageProcessor } from "./bot-message.js";
|
|
25
24
|
import { registerTelegramNativeCommands } from "./bot-native-commands.js";
|
|
@@ -45,11 +44,12 @@ export function getTelegramSequentialKey(ctx) {
|
|
|
45
44
|
return `telegram:${chatId}:control`;
|
|
46
45
|
return "telegram:control";
|
|
47
46
|
}
|
|
47
|
+
const isGroup = msg?.chat?.type === "group" || msg?.chat?.type === "supergroup";
|
|
48
|
+
const messageThreadId = msg?.message_thread_id;
|
|
48
49
|
const isForum = msg?.chat?.is_forum;
|
|
49
|
-
const threadId =
|
|
50
|
-
isForum,
|
|
51
|
-
|
|
52
|
-
});
|
|
50
|
+
const threadId = isGroup
|
|
51
|
+
? resolveTelegramForumThreadId({ isForum, messageThreadId })
|
|
52
|
+
: messageThreadId;
|
|
53
53
|
if (typeof chatId === "number") {
|
|
54
54
|
return threadId != null ? `telegram:${chatId}:topic:${threadId}` : `telegram:${chatId}`;
|
|
55
55
|
}
|
|
@@ -73,14 +73,15 @@ export function createTelegramBot(opts) {
|
|
|
73
73
|
network: telegramCfg.network,
|
|
74
74
|
});
|
|
75
75
|
const shouldProvideFetch = Boolean(fetchImpl);
|
|
76
|
+
// grammY's ApiClientOptions types still track `node-fetch` types; Node 22+ global fetch
|
|
77
|
+
// (undici) is structurally compatible at runtime but not assignable in TS.
|
|
78
|
+
const fetchForClient = fetchImpl;
|
|
76
79
|
const timeoutSeconds = typeof telegramCfg?.timeoutSeconds === "number" && Number.isFinite(telegramCfg.timeoutSeconds)
|
|
77
80
|
? Math.max(1, Math.floor(telegramCfg.timeoutSeconds))
|
|
78
81
|
: undefined;
|
|
79
82
|
const client = shouldProvideFetch || timeoutSeconds
|
|
80
83
|
? {
|
|
81
|
-
...(shouldProvideFetch && fetchImpl
|
|
82
|
-
? { fetch: fetchImpl }
|
|
83
|
-
: {}),
|
|
84
|
+
...(shouldProvideFetch && fetchImpl ? { fetch: fetchForClient } : {}),
|
|
84
85
|
...(timeoutSeconds ? { timeoutSeconds } : {}),
|
|
85
86
|
}
|
|
86
87
|
: undefined;
|
|
@@ -193,19 +194,22 @@ export function createTelegramBot(opts) {
|
|
|
193
194
|
const logger = getChildLogger({ module: "telegram-auto-reply" });
|
|
194
195
|
let botHasTopicsEnabled;
|
|
195
196
|
const resolveBotTopicsEnabled = async (ctx) => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
botHasTopicsEnabled = fromCtx.has_topics_enabled;
|
|
197
|
+
if (typeof ctx?.me?.has_topics_enabled === "boolean") {
|
|
198
|
+
botHasTopicsEnabled = ctx.me.has_topics_enabled;
|
|
199
199
|
return botHasTopicsEnabled;
|
|
200
200
|
}
|
|
201
201
|
if (typeof botHasTopicsEnabled === "boolean")
|
|
202
202
|
return botHasTopicsEnabled;
|
|
203
|
+
if (typeof bot.api.getMe !== "function") {
|
|
204
|
+
botHasTopicsEnabled = false;
|
|
205
|
+
return botHasTopicsEnabled;
|
|
206
|
+
}
|
|
203
207
|
try {
|
|
204
|
-
const me =
|
|
208
|
+
const me = await withTelegramApiErrorLogging({
|
|
205
209
|
operation: "getMe",
|
|
206
210
|
runtime,
|
|
207
211
|
fn: () => bot.api.getMe(),
|
|
208
|
-
})
|
|
212
|
+
});
|
|
209
213
|
botHasTopicsEnabled = Boolean(me?.has_topics_enabled);
|
|
210
214
|
}
|
|
211
215
|
catch (err) {
|
|
@@ -340,28 +344,25 @@ export function createTelegramBot(opts) {
|
|
|
340
344
|
senderLabel = `id:${user.id}`;
|
|
341
345
|
}
|
|
342
346
|
senderLabel = senderLabel || "unknown";
|
|
343
|
-
//
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
const resolvedThreadId = resolveTelegramForumThreadId({
|
|
347
|
-
isForum,
|
|
348
|
-
messageThreadId,
|
|
349
|
-
});
|
|
350
|
-
// Resolve agent route for session
|
|
347
|
+
// Reactions target a specific message_id; the Telegram Bot API does not include
|
|
348
|
+
// message_thread_id on MessageReactionUpdated, so we route to the chat-level
|
|
349
|
+
// session (forum topic routing is not available for reactions).
|
|
351
350
|
const isGroup = reaction.chat.type === "group" || reaction.chat.type === "supergroup";
|
|
351
|
+
const isForum = reaction.chat.is_forum === true;
|
|
352
|
+
const resolvedThreadId = isForum
|
|
353
|
+
? resolveTelegramForumThreadId({ isForum, messageThreadId: undefined })
|
|
354
|
+
: undefined;
|
|
352
355
|
const peerId = isGroup ? buildTelegramGroupPeerId(chatId, resolvedThreadId) : String(chatId);
|
|
356
|
+
const parentPeer = buildTelegramParentPeer({ isGroup, resolvedThreadId, chatId });
|
|
357
|
+
// Fresh config for bindings lookup; other routing inputs are payload-derived.
|
|
353
358
|
const route = resolveAgentRoute({
|
|
354
|
-
cfg,
|
|
359
|
+
cfg: loadConfig(),
|
|
355
360
|
channel: "telegram",
|
|
356
361
|
accountId: account.accountId,
|
|
357
362
|
peer: { kind: isGroup ? "group" : "dm", id: peerId },
|
|
363
|
+
parentPeer,
|
|
358
364
|
});
|
|
359
|
-
const
|
|
360
|
-
const dmThreadId = !isGroup ? resolvedThreadId : undefined;
|
|
361
|
-
const threadKeys = dmThreadId != null
|
|
362
|
-
? resolveThreadSessionKeys({ baseSessionKey, threadId: String(dmThreadId) })
|
|
363
|
-
: null;
|
|
364
|
-
const sessionKey = threadKeys?.sessionKey ?? baseSessionKey;
|
|
365
|
+
const sessionKey = route.sessionKey;
|
|
365
366
|
// Enqueue system event for each added reaction
|
|
366
367
|
for (const r of addedReactions) {
|
|
367
368
|
const emoji = r.emoji;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram inline button utilities for model selection.
|
|
3
|
+
*
|
|
4
|
+
* Callback data patterns (max 64 bytes for Telegram):
|
|
5
|
+
* - mdl_prov - show providers list
|
|
6
|
+
* - mdl_list_{prov}_{pg} - show models for provider (page N, 1-indexed)
|
|
7
|
+
* - mdl_sel_{provider/id} - select model
|
|
8
|
+
* - mdl_back - back to providers list
|
|
9
|
+
*/
|
|
10
|
+
const MODELS_PAGE_SIZE = 8;
|
|
11
|
+
const MAX_CALLBACK_DATA_BYTES = 64;
|
|
12
|
+
/**
|
|
13
|
+
* Parse a model callback_data string into a structured object.
|
|
14
|
+
* Returns null if the data doesn't match a known pattern.
|
|
15
|
+
*/
|
|
16
|
+
export function parseModelCallbackData(data) {
|
|
17
|
+
const trimmed = data.trim();
|
|
18
|
+
if (!trimmed.startsWith("mdl_")) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
if (trimmed === "mdl_prov" || trimmed === "mdl_back") {
|
|
22
|
+
return { type: trimmed === "mdl_prov" ? "providers" : "back" };
|
|
23
|
+
}
|
|
24
|
+
// mdl_list_{provider}_{page}
|
|
25
|
+
const listMatch = trimmed.match(/^mdl_list_([a-z0-9_-]+)_(\d+)$/i);
|
|
26
|
+
if (listMatch) {
|
|
27
|
+
const [, provider, pageStr] = listMatch;
|
|
28
|
+
const page = Number.parseInt(pageStr ?? "1", 10);
|
|
29
|
+
if (provider && Number.isFinite(page) && page >= 1) {
|
|
30
|
+
return { type: "list", provider, page };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// mdl_sel_{provider/model}
|
|
34
|
+
const selMatch = trimmed.match(/^mdl_sel_(.+)$/);
|
|
35
|
+
if (selMatch) {
|
|
36
|
+
const modelRef = selMatch[1];
|
|
37
|
+
if (modelRef) {
|
|
38
|
+
const slashIndex = modelRef.indexOf("/");
|
|
39
|
+
if (slashIndex > 0 && slashIndex < modelRef.length - 1) {
|
|
40
|
+
return {
|
|
41
|
+
type: "select",
|
|
42
|
+
provider: modelRef.slice(0, slashIndex),
|
|
43
|
+
model: modelRef.slice(slashIndex + 1),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Build provider selection keyboard with 2 providers per row.
|
|
52
|
+
*/
|
|
53
|
+
export function buildProviderKeyboard(providers) {
|
|
54
|
+
if (providers.length === 0) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const rows = [];
|
|
58
|
+
let currentRow = [];
|
|
59
|
+
for (const provider of providers) {
|
|
60
|
+
const button = {
|
|
61
|
+
text: `${provider.id} (${provider.count})`,
|
|
62
|
+
callback_data: `mdl_list_${provider.id}_1`,
|
|
63
|
+
};
|
|
64
|
+
currentRow.push(button);
|
|
65
|
+
if (currentRow.length === 2) {
|
|
66
|
+
rows.push(currentRow);
|
|
67
|
+
currentRow = [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Push any remaining button
|
|
71
|
+
if (currentRow.length > 0) {
|
|
72
|
+
rows.push(currentRow);
|
|
73
|
+
}
|
|
74
|
+
return rows;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Build model list keyboard with pagination and back button.
|
|
78
|
+
*/
|
|
79
|
+
export function buildModelsKeyboard(params) {
|
|
80
|
+
const { provider, models, currentModel, currentPage, totalPages } = params;
|
|
81
|
+
const pageSize = params.pageSize ?? MODELS_PAGE_SIZE;
|
|
82
|
+
if (models.length === 0) {
|
|
83
|
+
return [[{ text: "<< Back", callback_data: "mdl_back" }]];
|
|
84
|
+
}
|
|
85
|
+
const rows = [];
|
|
86
|
+
// Calculate page slice
|
|
87
|
+
const startIndex = (currentPage - 1) * pageSize;
|
|
88
|
+
const endIndex = Math.min(startIndex + pageSize, models.length);
|
|
89
|
+
const pageModels = models.slice(startIndex, endIndex);
|
|
90
|
+
// Model buttons - one per row
|
|
91
|
+
const currentModelId = currentModel?.includes("/")
|
|
92
|
+
? currentModel.split("/").slice(1).join("/")
|
|
93
|
+
: currentModel;
|
|
94
|
+
for (const model of pageModels) {
|
|
95
|
+
const callbackData = `mdl_sel_${provider}/${model}`;
|
|
96
|
+
// Skip models that would exceed Telegram's callback_data limit
|
|
97
|
+
if (Buffer.byteLength(callbackData, "utf8") > MAX_CALLBACK_DATA_BYTES) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const isCurrentModel = model === currentModelId;
|
|
101
|
+
const displayText = truncateModelId(model, 38);
|
|
102
|
+
const text = isCurrentModel ? `${displayText} ✓` : displayText;
|
|
103
|
+
rows.push([
|
|
104
|
+
{
|
|
105
|
+
text,
|
|
106
|
+
callback_data: callbackData,
|
|
107
|
+
},
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
// Pagination row
|
|
111
|
+
if (totalPages > 1) {
|
|
112
|
+
const paginationRow = [];
|
|
113
|
+
if (currentPage > 1) {
|
|
114
|
+
paginationRow.push({
|
|
115
|
+
text: "◀ Prev",
|
|
116
|
+
callback_data: `mdl_list_${provider}_${currentPage - 1}`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
paginationRow.push({
|
|
120
|
+
text: `${currentPage}/${totalPages}`,
|
|
121
|
+
callback_data: `mdl_list_${provider}_${currentPage}`, // noop
|
|
122
|
+
});
|
|
123
|
+
if (currentPage < totalPages) {
|
|
124
|
+
paginationRow.push({
|
|
125
|
+
text: "Next ▶",
|
|
126
|
+
callback_data: `mdl_list_${provider}_${currentPage + 1}`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
rows.push(paginationRow);
|
|
130
|
+
}
|
|
131
|
+
// Back button
|
|
132
|
+
rows.push([{ text: "<< Back", callback_data: "mdl_back" }]);
|
|
133
|
+
return rows;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Build "Browse providers" button for /model summary.
|
|
137
|
+
*/
|
|
138
|
+
export function buildBrowseProvidersButton() {
|
|
139
|
+
return [[{ text: "Browse providers", callback_data: "mdl_prov" }]];
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Truncate model ID for display, preserving end if too long.
|
|
143
|
+
*/
|
|
144
|
+
function truncateModelId(modelId, maxLen) {
|
|
145
|
+
if (modelId.length <= maxLen) {
|
|
146
|
+
return modelId;
|
|
147
|
+
}
|
|
148
|
+
// Show last part with ellipsis prefix
|
|
149
|
+
return `…${modelId.slice(-(maxLen - 1))}`;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get page size for model list pagination.
|
|
153
|
+
*/
|
|
154
|
+
export function getModelsPageSize() {
|
|
155
|
+
return MODELS_PAGE_SIZE;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Calculate total pages for a model list.
|
|
159
|
+
*/
|
|
160
|
+
export function calculateTotalPages(totalModels, pageSize) {
|
|
161
|
+
const size = pageSize ?? MODELS_PAGE_SIZE;
|
|
162
|
+
return size > 0 ? Math.ceil(totalModels / size) : 1;
|
|
163
|
+
}
|