feat: Add Telegram integration for agents#28330
Conversation
There was a problem hiding this comment.
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
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
9d21170 to
42d0025
Compare
Performance ComparisonComparing current → latest master → 14-day baseline Memory consumption baseline with starter plan resources
docker-stats
Idle baseline with Instance AI module loaded
How to read this table
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
f954bca to
6bb7d58
Compare
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>
6bb7d58 to
ab6268c
Compare
Bundle ReportChanges will increase total bundle size by 4.77kB (0.01%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: editor-ui-esmAssets Changed:
Files in
Files in
|
cda780f to
ab6268c
Compare
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.
- 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.
There was a problem hiding this comment.
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.
…gent-7-add-telegram-integration
yehorkardash
left a comment
There was a problem hiding this comment.
Looks good, just one small comment
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:
AgentChatIntegrationabstract base +ChatIntegrationRegistry(DI singleton). Each platform lives in one class underintegrations/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()callsintegration.normalizeComponents()from the registry instead of a hardcodednormalizeForPlatform.createRichInteractionTool()readssupportedComponentsanddescriptionfrom the registry.AgentChatBridgereads theneedsShortCallbackDataflag from the registry.AgentChatIntegrationsubclass + oneregistry.register()call inagents.module.ts.Backend — Telegram specifics:
@chat-adapter/telegramdependency.TelegramIntegrationauto-detects webhook vs polling mode based on whetherWEBHOOK_URLpoints to a public host. In webhook mode,onAfterConnectcalls Telegram'ssetWebhookAPI. In polling mode (local dev with no tunnel) the adapter usesgetUpdates.CallbackStore(async, delete-on-resolve, TtlMap-backed) shortens button payloads to fit Telegram's 64-bytecallback_datalimit.executeForChatPublishedunder the sameruntimeKey(agentId, userId, integrationType)as the draft path, so HITL button clicks on rich-interaction cards can find the runtime viaresumeForChat. 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.integrationTypethroughexecuteForChat/executeForChatPublished/reconstructFromConfig/injectRuntimeDependenciesso each platform gets its own runtime with the right rich-interaction tool capabilities.Frontend:
connectIntegration,disconnectIntegration,getIntegrationStatus) replace the Slack-only functions.AgentIntegrationsPanelis now data-driven over anintegrationConfigsarray — one entry per platform, same template.How to test:
telegramApicredential with the bot token.rich_interaction— buttons should render as an inline keyboard, and clicking one should resume the agent with the selected value.setWebhookcall); withWEBHOOK_URLpointing 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
release/backport(if the PR is an urgent fix that needs to be backported)