Skip to content

feat: Add Telegram integration for agents#28330

Merged
burivuhster merged 19 commits inton8n-agentsfrom
burivuhster/agent-7-add-telegram-integration
Apr 21, 2026
Merged

feat: Add Telegram integration for agents#28330
burivuhster merged 19 commits inton8n-agentsfrom
burivuhster/agent-7-add-telegram-integration

Conversation

@burivuhster
Copy link
Copy Markdown
Contributor

@burivuhster burivuhster commented Apr 10, 2026

Summary

Add Telegram as a second chat platform integration for n8n agents, alongside the existing Slack integration, and refactor the integration.

Backend — chat platform abstraction:

  • New AgentChatIntegration abstract base + ChatIntegrationRegistry (DI singleton). Each platform lives in one class under integrations/platforms/: SlackIntegration, TelegramIntegration. Subclasses own adapter construction, credential extraction, capability metadata, component normalization, and lifecycle hooks (onAfterConnect).
  • ChatIntegrationService.connect() lost its switch/extract methods and delegates to the registry. ComponentMapper.toCard() calls integration.normalizeComponents() from the registry instead of a hardcoded normalizeForPlatform. createRichInteractionTool() reads supportedComponents and description from the registry. AgentChatBridge reads the needsShortCallbackData flag from the registry.
  • Adding a new platform (Discord, Teams, …) is one AgentChatIntegration subclass + one registry.register() call in agents.module.ts.

Backend — Telegram specifics:

  • Add @chat-adapter/telegram dependency.
  • TelegramIntegration auto-detects webhook vs polling mode based on whether WEBHOOK_URL points to a public host. In webhook mode, onAfterConnect calls Telegram's setWebhook API. In polling mode (local dev with no tunnel) the adapter uses getUpdates.
  • Generic CallbackStore (async, delete-on-resolve, TtlMap-backed) shortens button payloads to fit Telegram's 64-byte callback_data limit.
  • Cache the reconstructed published runtime in executeForChatPublished under the same runtimeKey(agentId, userId, integrationType) as the draft path, so HITL button clicks on rich-interaction cards can find the runtime via resumeForChat. Without this, clicking a button on a published agent's card fails with "Agent is not compiled — cannot resume". Existing 30-min TTL bounds staleness after a republish.
  • Thread integrationType through executeForChat / executeForChatPublished / reconstructFromConfig / injectRuntimeDependencies so each platform gets its own runtime with the right rich-interaction tool capabilities.
  • Post-connect hook failures now shutdown the chat instance + dispose the bridge before propagating (no more leaked polling loops / adapter timers).
  • Expired/missing short-callback key posts a user-facing "This action is no longer available" message instead of silently dropping the click.

Frontend:

  • Generic integration API helpers (connectIntegration, disconnectIntegration, getIntegrationStatus) replace the Slack-only functions.
  • AgentIntegrationsPanel is now data-driven over an integrationConfigs array — one entry per platform, same template.

How to test:

  1. Create a Telegram bot via BotFather, add a telegramApi credential with the bot token.
  2. Navigate to an agent → Integrations tab → connect the Telegram credential.
  3. Message the bot in Telegram — agent should respond.
  4. Trigger a tool that uses rich_interaction — buttons should render as an inline keyboard, and clicking one should resume the agent with the selected value.
  5. Locally without a tunnel: connect works via polling mode (no setWebhook call); with WEBHOOK_URL pointing to a public host (e.g. ngrok), webhook mode is used.

Related Linear tickets, Github issues, and Community forum posts

https://linear.app/n8n/issue/AGENT-7

Review / Merge checklist

  • PR title and summary are descriptive. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.
  • PR Labeled with release/backport (if the PR is an urgent fix that needs to be backported)

@burivuhster burivuhster changed the title feat(core): Add Telegram integration for agents feat: Add Telegram integration for agents Apr 10, 2026
@n8n-assistant n8n-assistant Bot added core Enhancement outside /nodes-base and /editor-ui n8n team Authored by the n8n team labels Apr 10, 2026
@burivuhster burivuhster marked this pull request as ready for review April 10, 2026 14:30
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 11 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/modules/agents/integrations/callback-store.ts">

<violation number="1" location="packages/cli/src/modules/agents/integrations/callback-store.ts:49">
P2: Handle key collisions before storing. A repeated 8‑char hex key will overwrite an existing callback mapping, leading to lost or incorrect action resolution.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant UI as Agent UI (Frontend)
    participant ChatIntSvc as ChatIntegrationService
    participant Telegram as Telegram API
    participant Bridge as AgentChatBridge
    participant CBStore as CallbackStore
    participant AgentsSvc as AgentsService
    participant Mapper as ComponentMapper

    Note over UI, Telegram: Integration Setup
    UI->>ChatIntSvc: CHANGED: connectIntegration(type: 'telegram', credId)
    ChatIntSvc->>ChatIntSvc: Detect mode (Webhook vs Polling)
    opt NEW: Mode is Webhook
        ChatIntSvc->>Telegram: POST /setWebhook (with agent-specific URL)
    end

    Note over Telegram, AgentsSvc: Inbound Message & Agent Execution
    Telegram->>ChatIntSvc: Inbound Message / Webhook
    ChatIntSvc->>Bridge: Process message
    Bridge->>AgentsSvc: CHANGED: getRuntime(agentId, userId, integrationType: 'telegram')
    AgentsSvc->>AgentsSvc: NEW: createRichInteractionTool(integrationType)
    Note right of AgentsSvc: Tool config matches platform capabilities
    AgentsSvc-->>Bridge: Yield stream chunk (Suspend / Rich Interaction)

    Note over Bridge, Mapper: Outbound Rich Interaction (Normalization & Shortening)
    Bridge->>Mapper: CHANGED: toCard(payload, integrationType: 'telegram')
    Mapper->>Mapper: NEW: normalizeForPlatform() (e.g., select -> buttons)
    
    opt NEW: Integration type has callback size limits (Telegram/WhatsApp)
        Mapper->>CBStore: store(actionId, fullValue)
        CBStore-->>Mapper: return shortKey (8-char hex)
    end
    
    Mapper-->>Bridge: Final Card (normalized components + shortKeys)
    Bridge->>Telegram: Send message (Inline Keyboard)

    Note over Telegram, Bridge: Interaction Callback (Resolution)
    Telegram->>Bridge: Action Event (callback_data: shortKey)
    alt NEW: Integration uses CallbackStore
        Bridge->>CBStore: resolve(shortKey)
        CBStore-->>Bridge: return { actionId, fullValue }
    else Standard
        Bridge->>Bridge: Parse actionId/value from event
    end
    
    Bridge->>AgentsSvc: resumeForChat(runId, fullValue)
    AgentsSvc-->>Bridge: Next stream chunk
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread packages/cli/src/modules/agents/integrations/callback-store.ts Outdated
@burivuhster burivuhster force-pushed the burivuhster/agent-7-add-telegram-integration branch from 9d21170 to 42d0025 Compare April 15, 2026 07:40
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 15, 2026

Performance Comparison

Comparing currentlatest master14-day baseline

Memory consumption baseline with starter plan resources

Metric Current Latest Master Baseline (avg) vs Master vs Baseline Status
memory-heap-used-baseline 114.54 MB 114.41 MB 114.45 MB (σ 0.27) +0.1% +0.1%
memory-rss-baseline 343.49 MB 278.98 MB 289.99 MB (σ 41.20) +23.1% +18.4% ⚠️

docker-stats

Metric Current Latest Master Baseline (avg) vs Master vs Baseline Status
docker-image-size-runners 386.00 MB 386.00 MB 392.50 MB (σ 11.06) +0.0% -1.7%
docker-image-size-n8n 1280.00 MB 1269.76 MB 1273.60 MB (σ 10.49) +0.8% +0.5%

Idle baseline with Instance AI module loaded

Metric Current Latest Master Baseline (avg) vs Master vs Baseline Status
instance-ai-heap-used-baseline 186.75 MB 186.52 MB 186.43 MB (σ 0.26) +0.1% +0.2% ⚠️
instance-ai-rss-baseline 346.37 MB 389.20 MB 366.52 MB (σ 22.66) -11.0% -5.5%
How to read this table
  • Current: This PR's value (or latest master if PR perf tests haven't run)
  • Latest Master: Most recent nightly master measurement
  • Baseline: Rolling 14-day average from master
  • vs Master: PR impact (current vs latest master)
  • vs Baseline: Drift from baseline (current vs rolling avg)
  • Status: ✅ within 1σ | ⚠️ 1-2σ | 🔴 >2σ regression

@burivuhster burivuhster force-pushed the burivuhster/agent-7-add-telegram-integration branch from f954bca to 6bb7d58 Compare April 16, 2026 06:16
burivuhster and others added 7 commits April 20, 2026 10:54
Add Telegram as a second chat platform for n8n agents alongside Slack.

Backend:
- Add @chat-adapter/telegram dependency and ESM loader
- Add Telegram case in ChatIntegrationService with auto webhook registration
- Auto-detect webhook vs polling mode based on WEBHOOK_URL
- Add CallbackStore for platforms with short callback data limits
- Make createRichInteractionTool platform-aware with per-platform capabilities
- Add ComponentMapper fallback conversions for unsupported components
- Thread integrationType through agent execution for platform-specific runtimes

Frontend:
- Generalize integration API functions (connectIntegration, etc.)
- Refactor AgentIntegrationsPanel to data-driven multi-platform layout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Make store() and resolve() async for future Redis/DB swap
- Delete entries on resolve (one-time use)
- Amortize cleanup to every 100th store() call instead of every call

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Regenerate random key if it already exists in the map to prevent
overwriting an existing callback mapping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@burivuhster burivuhster force-pushed the burivuhster/agent-7-add-telegram-integration branch from 6bb7d58 to ab6268c Compare April 20, 2026 09:17
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Bundle Report

Changes will increase total bundle size by 4.77kB (0.01%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
editor-ui-esm 45.98MB 4.77kB (0.01%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: editor-ui-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/constants-*.js -158 bytes 3.14MB -0.01%
assets/index-*.js -1.69kB 1.31MB -0.13%
assets/ParameterInputList-*.js -848 bytes 1.27MB -0.07%
assets/users.store-*.js 618 bytes 1.06MB 0.06%
assets/core-*.js -27 bytes 632.69kB -0.0%
assets/useCanvasMapping-*.js -451 bytes 463.3kB -0.1%
assets/InstanceAiView-*.js -2.43kB 342.67kB -0.7%
assets/RunData-*.js -195 bytes 334.49kB -0.06%
assets/ParameterInputList-*.css -35 bytes 208.23kB -0.02%
assets/table-*.js 25.24kB 178.59kB 16.46% ⚠️
assets/InstanceAiView-*.css -251 bytes 162.59kB -0.15%
assets/NodeView-*.js -200 bytes 137.24kB -0.15%
assets/usePostMessageHandler-*.js -608 bytes 137.05kB -0.44%
assets/useRootStore-*.js 175 bytes 131.25kB 0.13%
assets/WorkflowLayout-*.js 38 bytes 127.92kB 0.03%
assets/router-*.js 7 bytes 121.48kB 0.01%
assets/canvas.eventBus-*.js -167 bytes 117.4kB -0.14%
assets/AgentBuilderView-*.js 1.6kB 116.97kB 1.39%
assets/NodeCreator-*.js -292 bytes 104.04kB -0.28%
assets/useCanvasOperations-*.js 33 bytes 95.38kB 0.03%
assets/VirtualSchema-*.js -38 bytes 94.47kB -0.04%
assets/NodeSettings-*.js -520 bytes 84.68kB -0.61%
assets/CanvasRunWorkflowButton-*.js -188 bytes 78.28kB -0.24%
assets/TriggerPanel-*.js -9 bytes 59.25kB -0.02%
assets/CreditWarningBanner-*.js -3.23kB 54.89kB -5.56%
assets/useLogsTreeExpand-*.js 54 bytes 41.24kB 0.13%
assets/NodeDetailsViewV2-*.js 18 bytes 38.03kB 0.05%
assets/AgentBuilderView-*.css -135 bytes 34.18kB -0.39%
assets/usePushConnection-*.js -130 bytes 31.37kB -0.41%
assets/useRunWorkflow-*.js 83 bytes 27.87kB 0.3%
assets/InstanceAiOptinModal-*.js 12.93kB 24.75kB 109.44% ⚠️
assets/assistant.store-*.js 46 bytes 19.37kB 0.24%
assets/SettingsLogStreamingView-*.js 43 bytes 17.48kB 0.25%
assets/InstanceAiOptinModal-*.css 3.18kB 12.45kB 34.27% ⚠️
assets/useActions-*.js 49 bytes 10.41kB 0.47%
assets/pushConnection.store-*.js -38 bytes 10.1kB -0.37%
assets/usePinnedData-*.js 23 bytes 9.13kB 0.25%
assets/WorkflowPreview-*.js -213 bytes 7.96kB -2.6%
assets/ChatInputBase-*.js -129 bytes 7.33kB -1.73%
assets/ContactAdministratorToInstall-*.js 44 bytes 5.92kB 0.75%
assets/useExecutionDebugging-*.js 76 bytes 5.62kB 1.37%
assets/nodeIcon-*.js 26 bytes 4.73kB 0.55%
assets/useAgentApi-*.js 30 bytes 3.57kB 0.85%
assets/useCalloutHelpers-*.js 48 bytes 3.44kB 1.42%
assets/NodeIcon-*.js -702 bytes 3.13kB -18.3%
assets/DemoLayout-*.js -735 bytes 2.77kB -20.96%
assets/useExpressionResolveCtx-*.js 55 bytes 1.68kB 3.38%
assets/checkbox-*.js (Deleted) -26.24kB 0 bytes -100.0% 🗑️

Files in assets/AgentBuilderView-*.js:

  • ./src/features/agents/components/AgentIntegrationsPanel.vue → Total Size: 375 bytes

Files in assets/useAgentApi-*.js:

  • ./src/features/agents/composables/useAgentApi.ts → Total Size: 3.08kB

@burivuhster burivuhster force-pushed the burivuhster/agent-7-add-telegram-integration branch 2 times, most recently from cda780f to ab6268c Compare April 20, 2026 09:49
executeForChatPublished reconstructed a fresh agent instance per call
without caching it, so any follow-up resumeForChat (button click from
a rich_interaction card) would call findRuntimeForAgent, find nothing,
and throw 'Agent is not compiled — cannot resume'. The bridge caught
the error and posted 'Something went wrong' to the chat.

Cache the reconstructed runtime under the same runtimeKey pattern used
by executeForChat (agentId:userId:integrationType). Integration traffic
still only ever runs the published version; drafts sit in their own
cache keys. Stale runtimes after a republish are bounded by the 30-min
TTL already applied to the runtimes map.
Comment thread packages/cli/src/modules/agents/integrations/callback-store.ts Outdated
Comment thread packages/cli/src/modules/agents/integrations/chat-integration.service.ts Outdated
Comment thread packages/cli/src/modules/agents/integrations/chat-integration.service.ts Outdated
Comment thread packages/cli/src/modules/agents/integrations/component-mapper.ts Outdated
Comment thread packages/cli/src/modules/agents/integrations/agent-chat-bridge.ts Outdated
Comment thread packages/cli/src/modules/agents/integrations/chat-integration.service.ts Outdated
Comment thread packages/cli/src/modules/agents/integrations/chat-integration.service.ts Outdated
Comment thread packages/cli/src/modules/agents/integrations/agent-chat-bridge.ts
- CallbackStore now wraps the shared TtlMap utility; it previously
  reimplemented lazy expiry and a custom sweep counter.
- AgentChatBridge's integrationType constructor parameter is required;
  the 'slack' default silently masked missing integration context.
- ChatIntegrationService.buildWebhookUrl now uses getWebhookBaseUrl so
  the Telegram webhook URL honours the WEBHOOK_URL env var the rest of
  n8n's webhook triggers respect.
- If the post-initialize hook (setWebhook) throws, shut the Chat
  instance and dispose the bridge before propagating — previously the
  polling loop and adapter timers would leak.
- When a Telegram callback key is missing (expired or one-time-used),
  post a short user-facing message instead of silently ignoring the
  click.

Addresses review comments from @yehorkardash on #28330.
Move platform-specific logic (adapter construction, credential extraction,
webhook registration, component normalization, capability metadata,
callback-size flag) out of ChatIntegrationService, ComponentMapper,
createRichInteractionTool, and AgentChatBridge into a per-platform
Integration subclass registered via IntegrationRegistry.

- integration.ts — Integration abstract base + IntegrationRegistry
- platforms/slack-integration.ts — adapter, credential extraction
- platforms/telegram-integration.ts — adapter, webhook registration via
  onAfterConnect hook, select/image component normalization, short-
  callback-data flag
- agents.module.ts registers both platforms at module init
- ChatIntegrationService.connect() loses its switch statement; adapter
  creation and post-connect hooks route through the registry
- ComponentMapper.toCard pulls normalization from the registry
- createRichInteractionTool pulls supportedComponents and description
  from the registry
- AgentChatBridge decides whether to allocate a CallbackStore based on
  the registry's needsShortCallbackData flag

Adding a new platform (Discord, Teams, …) is now: write one Integration
subclass and register it — no more hunts through four files.

Addresses review comments from @yehorkardash on #28330.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 9 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/modules/agents/integrations/platforms/telegram-integration.ts">

<violation number="1" location="packages/cli/src/modules/agents/integrations/platforms/telegram-integration.ts:89">
P1: Public URL detection for webhook mode is too weak and can misclassify private/loopback hosts as public, causing Telegram webhook mode to be selected when polling is required.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Prefix the symbol with the owning module so imports at call sites make
the scope clear. Pure rename — no behaviour change.
Copy link
Copy Markdown
Contributor

@yehorkardash yehorkardash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just one small comment

Comment thread packages/cli/src/modules/agents/integrations/agent-chat-integration.ts Outdated
@burivuhster burivuhster merged commit 2f87fd2 into n8n-agents Apr 21, 2026
52 of 53 checks passed
@burivuhster burivuhster deleted the burivuhster/agent-7-add-telegram-integration branch April 21, 2026 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Enhancement outside /nodes-base and /editor-ui n8n team Authored by the n8n team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants