@poolzin/pool-bot 2026.1.39 → 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/assets/chrome-extension/README.md +3 -3
- package/assets/chrome-extension/background.js +5 -5
- package/assets/chrome-extension/manifest.json +3 -3
- package/assets/chrome-extension/options.html +4 -4
- package/assets/chrome-extension/options.js +1 -1
- package/dist/acp/client.js +3 -3
- package/dist/acp/types.js +1 -1
- package/dist/agents/agent-paths.js +3 -3
- package/dist/agents/auth-profiles/paths.js +3 -3
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +10 -12
- package/dist/agents/cli-runner.js +2 -2
- package/dist/agents/cloudflare-ai-gateway.js +31 -0
- package/dist/agents/compaction.js +16 -2
- package/dist/agents/context-window-guard.js +13 -10
- package/dist/agents/context.js +4 -4
- package/dist/agents/docs-path.js +1 -1
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/minimax-vlm.js +1 -1
- package/dist/agents/model-auth.js +12 -1
- package/dist/agents/model-catalog.js +4 -4
- package/dist/agents/model-selection.js +31 -4
- package/dist/agents/models-config.js +3 -3
- package/dist/agents/models-config.providers.js +147 -39
- 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/openai.js +1 -1
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +9 -8
- package/dist/agents/pi-embedded-runner/model.js +63 -4
- package/dist/agents/pi-embedded-runner/run/attempt.js +27 -17
- package/dist/agents/pi-embedded-runner/run.js +203 -50
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-runner/tool-result-truncation.js +275 -0
- package/dist/agents/pi-embedded-runner/utils.js +1 -1
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-model-discovery.js +10 -0
- package/dist/agents/pi-tool-definition-adapter.js +50 -9
- package/dist/agents/pi-tools.before-tool-call.js +67 -0
- package/dist/agents/pi-tools.js +20 -10
- package/dist/agents/pi-tools.read.js +2 -2
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-file-repair.js +83 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- package/dist/agents/session-transcript-repair.js +68 -0
- 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/frontmatter.js +1 -1
- package/dist/agents/skills/workspace.js +2 -2
- package/dist/agents/skills-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/system-prompt.js +28 -4
- package/dist/agents/together-models.js +127 -0
- package/dist/agents/tool-images.js +1 -1
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +25 -1
- package/dist/agents/tools/browser-tool.js +3 -3
- package/dist/agents/tools/cron-tool.js +166 -19
- package/dist/agents/tools/discord-actions-presence.js +78 -0
- package/dist/agents/tools/image-tool.js +2 -2
- package/dist/agents/tools/memory-tool.js +93 -5
- 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/commands-registry.data.js +1 -1
- 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 +3 -2
- 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/commands-session.js +2 -2
- package/dist/auto-reply/reply/get-reply-run.js +16 -5
- package/dist/auto-reply/reply/groups.js +1 -1
- package/dist/auto-reply/reply/inbound-context.js +9 -1
- package/dist/auto-reply/reply/inbound-meta.js +130 -0
- package/dist/auto-reply/reply/model-selection.js +3 -3
- package/dist/auto-reply/reply/untrusted-context.js +15 -0
- package/dist/auto-reply/status.js +1 -1
- 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 +51 -8
- package/dist/browser/config.js +2 -11
- package/dist/browser/extension-relay.js +104 -43
- 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-context.js +2 -2
- package/dist/browser/server.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui.js +3 -3
- package/dist/channels/plugins/catalog.js +2 -2
- package/dist/channels/plugins/onboarding/imessage.js +1 -1
- package/dist/channels/plugins/onboarding/signal.js +1 -1
- package/dist/channels/plugins/onboarding/slack.js +4 -4
- package/dist/channels/plugins/onboarding/whatsapp.js +3 -3
- package/dist/channels/plugins/pairing-message.js +1 -1
- package/dist/channels/reply-prefix.js +8 -1
- package/dist/cli/browser-cli-extension.js +2 -2
- 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/docs-cli.js +1 -1
- package/dist/cli/gateway-cli/dev.js +1 -1
- package/dist/cli/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +30 -20
- package/dist/cli/nodes-cli/register.canvas.js +1 -1
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/plugins-cli.js +1 -1
- package/dist/cli/run-main.js +2 -2
- package/dist/cli/security-cli.js +1 -1
- package/dist/cli/tagline.js +1 -1
- package/dist/cli/update-cli.js +173 -52
- package/dist/cli/webhooks-cli.js +5 -5
- package/dist/commands/agent.js +1 -0
- package/dist/commands/agents.commands.add.js +1 -1
- package/dist/commands/auth-choice.apply.api-providers.js +305 -17
- package/dist/commands/auth-choice.apply.js +4 -1
- package/dist/commands/auth-choice.apply.plugin-provider.js +2 -2
- package/dist/commands/auth-choice.apply.xai.js +63 -0
- package/dist/commands/auth-choice.preferred-provider.js +7 -1
- package/dist/commands/configure.wizard.js +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/docs.js +1 -1
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-gateway-services.js +3 -3
- package/dist/commands/doctor-state-migrations.js +1 -1
- package/dist/commands/doctor-update.js +3 -3
- package/dist/commands/doctor.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.probe.js +2 -2
- package/dist/commands/models/list.registry.js +4 -4
- package/dist/commands/models/list.status-command.js +44 -24
- package/dist/commands/models/shared.js +15 -0
- package/dist/commands/onboard-auth.config-core.js +366 -28
- package/dist/commands/onboard-auth.credentials.js +71 -9
- package/dist/commands/onboard-auth.js +3 -3
- package/dist/commands/onboard-auth.models.js +26 -24
- 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 +146 -9
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/commands/status-all/report-lines.js +1 -1
- package/dist/commands/status.command.js +1 -1
- package/dist/commands/uninstall.js +3 -3
- package/dist/compat/legacy-names.js +1 -1
- package/dist/config/defaults.js +3 -2
- package/dist/config/io.js +3 -3
- 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 +3 -3
- package/dist/config/sessions/store.js +291 -23
- package/dist/config/types.memory.js +1 -0
- package/dist/config/version.js +4 -4
- 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/daemon/constants.js +7 -7
- package/dist/daemon/inspect.js +6 -6
- package/dist/daemon/systemd-unit.js +1 -1
- 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/live-image-probe.js +1 -66
- package/dist/gateway/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- package/dist/gateway/openai-http.js +2 -2
- package/dist/gateway/openresponses-http.js +4 -4
- 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-discovery.js +2 -2
- package/dist/gateway/server-http.js +110 -12
- 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 +7 -3
- 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/hooks/frontmatter.js +1 -1
- package/dist/hooks/hooks-status.js +1 -1
- package/dist/hooks/install.js +2 -2
- package/dist/hooks/loader.js +1 -1
- package/dist/hooks/workspace.js +3 -3
- 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/index.js +2 -2
- package/dist/infra/bonjour-discovery.js +131 -70
- package/dist/infra/bonjour.js +3 -3
- 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/path-env.js +3 -3
- package/dist/infra/poolbot-root.js +43 -1
- package/dist/infra/provider-usage.fetch.minimax.js +1 -1
- package/dist/infra/restart.js +1 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- package/dist/infra/tailscale.js +1 -1
- 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/macos/relay.js +2 -2
- package/dist/media/fetch.js +81 -58
- package/dist/media/input-files.js +1 -1
- package/dist/media/mime.js +4 -0
- package/dist/media/png-encode.js +74 -0
- 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 +4 -4
- 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/backend-config.js +207 -0
- package/dist/memory/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +29 -17
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +155 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/memory/types.js +1 -0
- package/dist/node-host/runner.js +36 -26
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/pairing/pairing-messages.js +1 -1
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/discovery.js +1 -1
- package/dist/plugins/install.js +2 -2
- package/dist/plugins/source-display.js +51 -0
- package/dist/plugins/update.js +1 -1
- 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/audit.js +2 -2
- 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/shared/text/reasoning-tags.js +52 -7
- package/dist/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +145 -0
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +38 -11
- 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/test-helpers/workspace.js +11 -0
- package/dist/test-utils/channel-plugins.js +82 -0
- package/dist/test-utils/ports.js +73 -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/shell-argv.js +61 -0
- package/dist/utils/transcript-tools.js +58 -0
- package/dist/utils.js +55 -14
- package/dist/version.js +42 -5
- package/dist/web/qr-image.js +1 -61
- package/dist/wizard/onboarding.finalize.js +7 -7
- package/dist/wizard/onboarding.js +3 -3
- package/docs/RELEASE_WORKFOTS_COMPARISON.md +3 -3
- package/docs/_config.yml +2 -2
- package/docs/_layouts/default.html +9 -9
- package/docs/concepts/typebox.md +1 -1
- package/docs/docs.json +1 -1
- package/docs/northflank.mdx +7 -7
- package/docs/railway.mdx +3 -3
- package/docs/render.mdx +5 -5
- package/docs/start/lore.md +2 -2
- package/extensions/bluebubbles/index.ts +2 -2
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/bluebubbles/src/accounts.ts +8 -8
- package/extensions/bluebubbles/src/actions.test.ts +22 -22
- package/extensions/bluebubbles/src/actions.ts +5 -5
- package/extensions/bluebubbles/src/attachments.ts +2 -2
- package/extensions/bluebubbles/src/channel.ts +16 -16
- package/extensions/bluebubbles/src/chat.ts +2 -2
- package/extensions/bluebubbles/src/media-send.ts +2 -2
- package/extensions/bluebubbles/src/monitor.test.ts +46 -46
- package/extensions/bluebubbles/src/monitor.ts +5 -5
- package/extensions/bluebubbles/src/onboarding.ts +7 -7
- package/extensions/bluebubbles/src/reactions.ts +2 -2
- package/extensions/bluebubbles/src/send.ts +2 -2
- package/extensions/copilot-proxy/README.md +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/index.ts +2 -2
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/diagnostics-otel/src/service.ts +3 -3
- package/extensions/discord/index.ts +2 -2
- package/extensions/discord/package.json +1 -1
- package/extensions/google-antigravity-auth/README.md +1 -1
- package/extensions/google-antigravity-auth/index.ts +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/README.md +1 -1
- package/extensions/google-gemini-cli-auth/oauth.ts +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/index.ts +3 -3
- package/extensions/googlechat/package.json +1 -1
- package/extensions/googlechat/src/accounts.ts +8 -8
- package/extensions/googlechat/src/actions.ts +6 -6
- package/extensions/googlechat/src/channel.ts +21 -21
- package/extensions/googlechat/src/monitor.ts +8 -8
- package/extensions/googlechat/src/onboarding.ts +10 -10
- package/extensions/imessage/index.ts +2 -2
- package/extensions/imessage/package.json +1 -1
- package/extensions/line/index.ts +2 -2
- package/extensions/line/package.json +1 -1
- package/extensions/line/src/card-command.ts +2 -2
- package/extensions/line/src/channel.logout.test.ts +4 -4
- package/extensions/line/src/channel.sendPayload.test.ts +8 -8
- package/extensions/line/src/channel.ts +3 -3
- package/extensions/llm-task/README.md +3 -3
- package/extensions/llm-task/index.ts +2 -2
- package/extensions/llm-task/package.json +1 -1
- package/extensions/llm-task/src/llm-task-tool.ts +4 -4
- package/extensions/lobster/README.md +6 -6
- package/extensions/lobster/index.ts +2 -2
- package/extensions/lobster/src/lobster-tool.test.ts +4 -4
- package/extensions/lobster/src/lobster-tool.ts +2 -2
- package/extensions/matrix/index.ts +2 -2
- package/extensions/matrix/package.json +1 -1
- package/extensions/matrix/src/matrix/client/config.ts +1 -1
- package/extensions/matrix/src/matrix/monitor/handler.ts +1 -1
- package/extensions/matrix/src/onboarding.ts +1 -1
- package/extensions/mattermost/index.ts +2 -2
- package/extensions/mattermost/package.json +1 -1
- package/extensions/mattermost/src/mattermost/accounts.ts +8 -8
- package/extensions/mattermost/src/mattermost/monitor-helpers.ts +5 -5
- package/extensions/mattermost/src/mattermost/monitor.ts +2 -2
- package/extensions/mattermost/src/onboarding-helpers.ts +3 -3
- package/extensions/mattermost/src/onboarding.ts +2 -2
- package/extensions/memory-core/index.ts +2 -2
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/index.ts +3 -3
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/msteams/index.ts +2 -2
- package/extensions/msteams/package.json +1 -1
- package/extensions/msteams/src/channel.directory.test.ts +2 -2
- package/extensions/msteams/src/channel.ts +2 -2
- package/extensions/msteams/src/graph-upload.ts +4 -4
- package/extensions/msteams/src/monitor-handler.ts +2 -2
- package/extensions/msteams/src/monitor.ts +2 -2
- package/extensions/msteams/src/onboarding.ts +9 -9
- package/extensions/msteams/src/reply-dispatcher.ts +2 -2
- package/extensions/msteams/src/send-context.ts +2 -2
- package/extensions/msteams/src/send.ts +4 -4
- package/extensions/nextcloud-talk/index.ts +2 -2
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nextcloud-talk/src/channel.ts +7 -7
- package/extensions/nextcloud-talk/src/inbound.ts +7 -7
- package/extensions/nextcloud-talk/src/onboarding.ts +1 -1
- package/extensions/nostr/README.md +2 -2
- package/extensions/nostr/index.ts +5 -5
- package/extensions/nostr/package.json +1 -1
- package/extensions/nostr/src/types.ts +4 -4
- package/extensions/open-prose/index.ts +2 -2
- package/extensions/qwen-portal-auth/README.md +1 -1
- package/extensions/signal/index.ts +2 -2
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/index.ts +2 -2
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/index.ts +2 -2
- package/extensions/telegram/package.json +1 -1
- package/extensions/telegram/src/channel.ts +2 -2
- package/extensions/tlon/README.md +2 -2
- package/extensions/tlon/index.ts +2 -2
- package/extensions/tlon/package.json +1 -1
- package/extensions/tlon/src/channel.ts +13 -13
- package/extensions/tlon/src/monitor/index.ts +3 -3
- package/extensions/tlon/src/onboarding.ts +3 -3
- package/extensions/tlon/src/types.ts +3 -3
- package/extensions/twitch/README.md +1 -1
- package/extensions/twitch/index.ts +2 -2
- package/extensions/twitch/package.json +1 -1
- package/extensions/twitch/src/config.ts +3 -3
- package/extensions/twitch/src/monitor.ts +3 -3
- package/extensions/twitch/src/onboarding.ts +9 -9
- package/extensions/twitch/src/outbound.test.ts +2 -2
- package/extensions/twitch/src/plugin.test.ts +2 -2
- package/extensions/twitch/src/plugin.ts +8 -8
- package/extensions/twitch/src/send.test.ts +2 -2
- package/extensions/twitch/src/send.ts +4 -4
- package/extensions/twitch/src/token.test.ts +8 -8
- package/extensions/twitch/src/token.ts +3 -3
- package/extensions/twitch/src/twitch-client.ts +3 -3
- package/extensions/twitch/src/types.ts +3 -3
- package/extensions/twitch/src/utils/markdown.ts +1 -1
- package/extensions/voice-call/README.md +3 -3
- package/extensions/voice-call/package.json +1 -1
- package/extensions/voice-call/src/core-bridge.ts +2 -2
- package/extensions/voice-call/src/response-generator.ts +1 -1
- package/extensions/whatsapp/index.ts +2 -2
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/README.md +1 -1
- package/extensions/zalo/index.ts +2 -2
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalo/src/accounts.ts +8 -8
- package/extensions/zalo/src/actions.ts +4 -4
- package/extensions/zalo/src/channel.directory.test.ts +2 -2
- package/extensions/zalo/src/channel.ts +18 -18
- package/extensions/zalo/src/monitor.ts +9 -9
- package/extensions/zalo/src/monitor.webhook.test.ts +2 -2
- package/extensions/zalo/src/onboarding.ts +24 -24
- package/extensions/zalo/src/send.ts +2 -2
- package/extensions/zalouser/README.md +2 -2
- package/extensions/zalouser/index.ts +2 -2
- package/extensions/zalouser/package.json +1 -1
- package/extensions/zalouser/src/accounts.ts +9 -9
- package/extensions/zalouser/src/channel.ts +24 -24
- package/extensions/zalouser/src/monitor.ts +4 -4
- package/extensions/zalouser/src/onboarding.ts +28 -28
- package/package.json +13 -251
- package/skills/nano-banana-pro/scripts/generate_image.py +1 -1
- package/skills/tmux/scripts/find-sessions.sh +1 -1
- package/CHANGELOG.md +0 -102
- package/README-header.png +0 -0
- package/git-hooks/pre-commit +0 -4
- package/scripts/format-staged.js +0 -148
- package/scripts/postinstall.js +0 -300
- package/scripts/setup-git-hooks.js +0 -96
|
@@ -11,6 +11,7 @@ import { formatLocationText, toLocationContext } from "../channels/location.js";
|
|
|
11
11
|
import { recordInboundSession } from "../channels/session.js";
|
|
12
12
|
import { formatCliCommand } from "../cli/command-format.js";
|
|
13
13
|
import { readSessionUpdatedAt, resolveStorePath } from "../config/sessions.js";
|
|
14
|
+
import { loadConfig } from "../config/config.js";
|
|
14
15
|
import { logVerbose, shouldLogVerbose } from "../globals.js";
|
|
15
16
|
import { recordChannelActivity } from "../infra/channel-activity.js";
|
|
16
17
|
import { resolveAgentRoute } from "../routing/resolve-route.js";
|
|
@@ -20,7 +21,7 @@ import { resolveMentionGatingWithBypass } from "../channels/mention-gating.js";
|
|
|
20
21
|
import { resolveControlCommandGate } from "../channels/command-gating.js";
|
|
21
22
|
import { logInboundDrop } from "../channels/logging.js";
|
|
22
23
|
import { withTelegramApiErrorLogging } from "./api-logging.js";
|
|
23
|
-
import { buildGroupLabel, buildSenderLabel, buildSenderName, buildTelegramGroupFrom, buildTelegramGroupPeerId, buildTypingThreadParams, expandTextLinks, normalizeForwardedContext, describeReplyTarget, extractTelegramLocation, hasBotMention,
|
|
24
|
+
import { buildGroupLabel, buildSenderLabel, buildSenderName, buildTelegramGroupFrom, buildTelegramGroupPeerId, buildTelegramParentPeer, buildTypingThreadParams, expandTextLinks, normalizeForwardedContext, describeReplyTarget, extractTelegramLocation, hasBotMention, resolveTelegramThreadSpec, } from "./bot/helpers.js";
|
|
24
25
|
import { firstDefined, isSenderAllowed, normalizeAllowFromWithStore, resolveSenderAllowMatch, } from "./bot-access.js";
|
|
25
26
|
import { upsertTelegramPairingRequest } from "./pairing-store.js";
|
|
26
27
|
async function resolveStickerVisionSupport(params) {
|
|
@@ -50,23 +51,28 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
50
51
|
const isGroup = msg.chat.type === "group" || msg.chat.type === "supergroup";
|
|
51
52
|
const messageThreadId = msg.message_thread_id;
|
|
52
53
|
const isForum = msg.chat.is_forum === true;
|
|
53
|
-
const
|
|
54
|
+
const threadSpec = resolveTelegramThreadSpec({
|
|
55
|
+
isGroup,
|
|
54
56
|
isForum,
|
|
55
57
|
messageThreadId,
|
|
56
58
|
});
|
|
59
|
+
const resolvedThreadId = threadSpec.scope === "forum" ? threadSpec.id : undefined;
|
|
60
|
+
const replyThreadId = threadSpec.id;
|
|
57
61
|
const { groupConfig, topicConfig } = resolveTelegramGroupConfig(chatId, resolvedThreadId);
|
|
58
62
|
const peerId = isGroup ? buildTelegramGroupPeerId(chatId, resolvedThreadId) : String(chatId);
|
|
63
|
+
const parentPeer = buildTelegramParentPeer({ isGroup, resolvedThreadId, chatId });
|
|
59
64
|
const route = resolveAgentRoute({
|
|
60
|
-
cfg,
|
|
65
|
+
cfg: loadConfig(),
|
|
61
66
|
channel: "telegram",
|
|
62
67
|
accountId: account.accountId,
|
|
63
68
|
peer: {
|
|
64
69
|
kind: isGroup ? "group" : "dm",
|
|
65
70
|
id: peerId,
|
|
66
71
|
},
|
|
72
|
+
parentPeer,
|
|
67
73
|
});
|
|
68
74
|
const baseSessionKey = route.sessionKey;
|
|
69
|
-
const dmThreadId =
|
|
75
|
+
const dmThreadId = threadSpec.scope === "dm" ? threadSpec.id : undefined;
|
|
70
76
|
const threadKeys = dmThreadId != null
|
|
71
77
|
? resolveThreadSessionKeys({ baseSessionKey, threadId: String(dmThreadId) })
|
|
72
78
|
: null;
|
|
@@ -90,14 +96,14 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
90
96
|
const sendTyping = async () => {
|
|
91
97
|
await withTelegramApiErrorLogging({
|
|
92
98
|
operation: "sendChatAction",
|
|
93
|
-
fn: () => bot.api.sendChatAction(chatId, "typing", buildTypingThreadParams(
|
|
99
|
+
fn: () => bot.api.sendChatAction(chatId, "typing", buildTypingThreadParams(replyThreadId)),
|
|
94
100
|
});
|
|
95
101
|
};
|
|
96
102
|
const sendRecordVoice = async () => {
|
|
97
103
|
try {
|
|
98
104
|
await withTelegramApiErrorLogging({
|
|
99
105
|
operation: "sendChatAction",
|
|
100
|
-
fn: () => bot.api.sendChatAction(chatId, "record_voice", buildTypingThreadParams(
|
|
106
|
+
fn: () => bot.api.sendChatAction(chatId, "record_voice", buildTypingThreadParams(replyThreadId)),
|
|
101
107
|
});
|
|
102
108
|
}
|
|
103
109
|
catch (err) {
|
|
@@ -109,7 +115,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
109
115
|
if (dmPolicy === "disabled")
|
|
110
116
|
return null;
|
|
111
117
|
if (dmPolicy !== "open") {
|
|
112
|
-
const
|
|
118
|
+
const senderUserId = msg.from?.id != null ? String(msg.from.id) : null;
|
|
119
|
+
const candidate = senderUserId ?? String(chatId);
|
|
113
120
|
const senderUsername = msg.from?.username ?? "";
|
|
114
121
|
const allowMatch = resolveSenderAllowMatch({
|
|
115
122
|
allow: effectiveDmAllow,
|
|
@@ -131,7 +138,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
131
138
|
});
|
|
132
139
|
if (created) {
|
|
133
140
|
logger.info({
|
|
134
|
-
chatId:
|
|
141
|
+
chatId: String(chatId),
|
|
142
|
+
senderUserId: senderUserId ?? undefined,
|
|
135
143
|
username: from?.username,
|
|
136
144
|
firstName: from?.first_name,
|
|
137
145
|
lastName: from?.last_name,
|
|
@@ -141,7 +149,7 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
141
149
|
await withTelegramApiErrorLogging({
|
|
142
150
|
operation: "sendMessage",
|
|
143
151
|
fn: () => bot.api.sendMessage(chatId, [
|
|
144
|
-
"
|
|
152
|
+
"Poolbot: access not configured.",
|
|
145
153
|
"",
|
|
146
154
|
`Your Telegram user id: ${telegramUserId}`,
|
|
147
155
|
"",
|
|
@@ -201,6 +209,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
201
209
|
placeholder = "<media:image>";
|
|
202
210
|
else if (msg.video)
|
|
203
211
|
placeholder = "<media:video>";
|
|
212
|
+
else if (msg.video_note)
|
|
213
|
+
placeholder = "<media:video>";
|
|
204
214
|
else if (msg.audio || msg.voice)
|
|
205
215
|
placeholder = "<media:audio>";
|
|
206
216
|
else if (msg.document)
|
|
@@ -326,7 +336,9 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
326
336
|
const replyTarget = describeReplyTarget(msg);
|
|
327
337
|
const forwardOrigin = normalizeForwardedContext(msg);
|
|
328
338
|
const replySuffix = replyTarget
|
|
329
|
-
?
|
|
339
|
+
? replyTarget.kind === "quote"
|
|
340
|
+
? `\n\n[Quoting ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n"${replyTarget.body}"\n[/Quoting]`
|
|
341
|
+
: `\n\n[Replying to ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n${replyTarget.body}\n[/Replying]`
|
|
330
342
|
: "";
|
|
331
343
|
const forwardPrefix = forwardOrigin
|
|
332
344
|
? `[Forwarded from ${forwardOrigin.from}${forwardOrigin.date ? ` at ${new Date(forwardOrigin.date * 1000).toISOString()}` : ""}]\n`
|
|
@@ -383,9 +395,17 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
383
395
|
].filter((entry) => Boolean(entry));
|
|
384
396
|
const groupSystemPrompt = systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
|
|
385
397
|
const commandBody = normalizeCommandBody(rawBody, { botUsername });
|
|
398
|
+
const inboundHistory = isGroup && historyKey && historyLimit > 0
|
|
399
|
+
? (groupHistories.get(historyKey) ?? []).map((entry) => ({
|
|
400
|
+
sender: entry.sender,
|
|
401
|
+
body: entry.body,
|
|
402
|
+
timestamp: entry.timestamp,
|
|
403
|
+
}))
|
|
404
|
+
: undefined;
|
|
386
405
|
const ctxPayload = finalizeInboundContext({
|
|
387
406
|
Body: combinedBody,
|
|
388
407
|
RawBody: rawBody,
|
|
408
|
+
BodyForAgent: bodyText,
|
|
389
409
|
CommandBody: commandBody,
|
|
390
410
|
From: isGroup ? buildTelegramGroupFrom(chatId, resolvedThreadId) : `telegram:${chatId}`,
|
|
391
411
|
To: `telegram:${chatId}`,
|
|
@@ -404,12 +424,15 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
404
424
|
ReplyToId: replyTarget?.id,
|
|
405
425
|
ReplyToBody: replyTarget?.body,
|
|
406
426
|
ReplyToSender: replyTarget?.sender,
|
|
427
|
+
ReplyToIsQuote: replyTarget?.kind === "quote" ? true : undefined,
|
|
407
428
|
ForwardedFrom: forwardOrigin?.from,
|
|
408
429
|
ForwardedFromType: forwardOrigin?.fromType,
|
|
409
430
|
ForwardedFromId: forwardOrigin?.fromId,
|
|
410
431
|
ForwardedFromUsername: forwardOrigin?.fromUsername,
|
|
411
432
|
ForwardedFromTitle: forwardOrigin?.fromTitle,
|
|
412
433
|
ForwardedFromSignature: forwardOrigin?.fromSignature,
|
|
434
|
+
ForwardedFromChatType: forwardOrigin?.fromChatType,
|
|
435
|
+
ForwardedFromMessageId: forwardOrigin?.fromMessageId,
|
|
413
436
|
ForwardedDate: forwardOrigin?.date ? forwardOrigin.date * 1000 : undefined,
|
|
414
437
|
Timestamp: msg.date ? msg.date * 1000 : undefined,
|
|
415
438
|
WasMentioned: isGroup ? effectiveWasMentioned : undefined,
|
|
@@ -435,7 +458,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
435
458
|
Sticker: allMedia[0]?.stickerMetadata,
|
|
436
459
|
...(locationData ? toLocationContext(locationData) : undefined),
|
|
437
460
|
CommandAuthorized: commandAuthorized,
|
|
438
|
-
|
|
461
|
+
InboundHistory: inboundHistory,
|
|
462
|
+
MessageThreadId: threadSpec.id,
|
|
439
463
|
IsForum: isForum,
|
|
440
464
|
// Originating channel for reply routing.
|
|
441
465
|
OriginatingChannel: "telegram",
|
|
@@ -451,6 +475,7 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
451
475
|
channel: "telegram",
|
|
452
476
|
to: String(chatId),
|
|
453
477
|
accountId: route.accountId,
|
|
478
|
+
threadId: dmThreadId != null ? String(dmThreadId) : undefined,
|
|
454
479
|
}
|
|
455
480
|
: undefined,
|
|
456
481
|
onRecordError: (err) => {
|
|
@@ -477,6 +502,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
|
|
|
477
502
|
chatId,
|
|
478
503
|
isGroup,
|
|
479
504
|
resolvedThreadId,
|
|
505
|
+
threadSpec,
|
|
506
|
+
replyThreadId,
|
|
480
507
|
isForum,
|
|
481
508
|
historyKey,
|
|
482
509
|
historyLimit,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import { EmbeddedBlockChunker } from "../agents/pi-embedded-block-chunker.js";
|
|
1
|
+
import { resolveAgentDir } from "../agents/agent-scope.js";
|
|
3
2
|
import { findModelInCatalog, loadModelCatalog, modelSupportsVision, } from "../agents/model-catalog.js";
|
|
4
3
|
import { resolveDefaultModelForAgent } from "../agents/model-selection.js";
|
|
4
|
+
import { EmbeddedBlockChunker } from "../agents/pi-embedded-block-chunker.js";
|
|
5
5
|
import { resolveChunkMode } from "../auto-reply/chunk.js";
|
|
6
6
|
import { clearHistoryEntriesIfEnabled } from "../auto-reply/reply/history.js";
|
|
7
7
|
import { dispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.js";
|
|
@@ -9,13 +9,13 @@ import { removeAckReactionAfterReply } from "../channels/ack-reactions.js";
|
|
|
9
9
|
import { logAckFailure, logTypingFailure } from "../channels/logging.js";
|
|
10
10
|
import { createReplyPrefixContext } from "../channels/reply-prefix.js";
|
|
11
11
|
import { createTypingCallbacks } from "../channels/typing.js";
|
|
12
|
-
import { danger, logVerbose } from "../globals.js";
|
|
13
12
|
import { resolveMarkdownTableMode } from "../config/markdown-tables.js";
|
|
13
|
+
import { danger, logVerbose } from "../globals.js";
|
|
14
14
|
import { deliverReplies } from "./bot/delivery.js";
|
|
15
15
|
import { resolveTelegramDraftStreamingChunking } from "./draft-chunking.js";
|
|
16
16
|
import { createTelegramDraftStream } from "./draft-stream.js";
|
|
17
17
|
import { cacheSticker, describeStickerImage } from "./sticker-cache.js";
|
|
18
|
-
|
|
18
|
+
const EMPTY_RESPONSE_FALLBACK = "No response generated. Please try again.";
|
|
19
19
|
async function resolveStickerVisionSupport(cfg, agentId) {
|
|
20
20
|
try {
|
|
21
21
|
const catalog = await loadModelCatalog({ config: cfg });
|
|
@@ -118,7 +118,7 @@ export const dispatchTelegramMessage = async ({ context, bot, cfg, runtime, repl
|
|
|
118
118
|
// Handle uncached stickers: get a dedicated vision description before dispatch
|
|
119
119
|
// This ensures we cache a raw description rather than a conversational response
|
|
120
120
|
const sticker = ctxPayload.Sticker;
|
|
121
|
-
if (sticker?.fileUniqueId && ctxPayload.MediaPath) {
|
|
121
|
+
if (sticker?.fileId && sticker.fileUniqueId && ctxPayload.MediaPath) {
|
|
122
122
|
const agentDir = resolveAgentDir(cfg, route.agentId);
|
|
123
123
|
const stickerSupportsVision = await resolveStickerVisionSupport(cfg, route.agentId);
|
|
124
124
|
let description = sticker.cachedDescription ?? null;
|
|
@@ -150,18 +150,28 @@ export const dispatchTelegramMessage = async ({ context, bot, cfg, runtime, repl
|
|
|
150
150
|
ctxPayload.MediaTypes = undefined;
|
|
151
151
|
}
|
|
152
152
|
// Cache the description for future encounters
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
153
|
+
if (sticker.fileId) {
|
|
154
|
+
cacheSticker({
|
|
155
|
+
fileId: sticker.fileId,
|
|
156
|
+
fileUniqueId: sticker.fileUniqueId,
|
|
157
|
+
emoji: sticker.emoji,
|
|
158
|
+
setName: sticker.setName,
|
|
159
|
+
description,
|
|
160
|
+
cachedAt: new Date().toISOString(),
|
|
161
|
+
receivedFrom: ctxPayload.From,
|
|
162
|
+
});
|
|
163
|
+
logVerbose(`telegram: cached sticker description for ${sticker.fileUniqueId}`);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
logVerbose(`telegram: skipped sticker cache (missing fileId)`);
|
|
167
|
+
}
|
|
163
168
|
}
|
|
164
169
|
}
|
|
170
|
+
// TODO: pass replyQuoteText to deliverReplies once delivery.ts supports it
|
|
171
|
+
const _replyQuoteText = ctxPayload.ReplyToIsQuote && ctxPayload.ReplyToBody
|
|
172
|
+
? ctxPayload.ReplyToBody.trim() || undefined
|
|
173
|
+
: undefined;
|
|
174
|
+
void _replyQuoteText;
|
|
165
175
|
const { queuedFinal } = await dispatchReplyWithBufferedBlockDispatcher({
|
|
166
176
|
ctx: ctxPayload,
|
|
167
177
|
cfg,
|
|
@@ -219,7 +229,30 @@ export const dispatchTelegramMessage = async ({ context, bot, cfg, runtime, repl
|
|
|
219
229
|
},
|
|
220
230
|
});
|
|
221
231
|
draftStream?.stop();
|
|
232
|
+
let sentFallback = false;
|
|
222
233
|
if (!queuedFinal) {
|
|
234
|
+
try {
|
|
235
|
+
await deliverReplies({
|
|
236
|
+
replies: [{ text: EMPTY_RESPONSE_FALLBACK }],
|
|
237
|
+
chatId: String(chatId),
|
|
238
|
+
token: opts.token,
|
|
239
|
+
runtime,
|
|
240
|
+
bot,
|
|
241
|
+
replyToMode,
|
|
242
|
+
textLimit,
|
|
243
|
+
messageThreadId: resolvedThreadId,
|
|
244
|
+
tableMode,
|
|
245
|
+
chunkMode,
|
|
246
|
+
linkPreview: telegramCfg.linkPreview,
|
|
247
|
+
});
|
|
248
|
+
sentFallback = true;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Fallback delivery failed; proceed without it
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const hasFinalResponse = queuedFinal || sentFallback;
|
|
255
|
+
if (!hasFinalResponse) {
|
|
223
256
|
if (isGroup && historyKey) {
|
|
224
257
|
clearHistoryEntriesIfEnabled({ historyMap: groupHistories, historyKey, limit: historyLimit });
|
|
225
258
|
}
|
|
@@ -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;
|