close
Skip to content

feat(telegram): support multiple bot accounts per gateway - #2203

Merged
chenmingwei23 merged 1 commit into
mainfrom
feat/multi-telegram-bot
Aug 9, 2026
Merged

feat(telegram): support multiple bot accounts per gateway#2203
chenmingwei23 merged 1 commit into
mainfrom
feat/multi-telegram-bot

Conversation

@chenmingwei23

Copy link
Copy Markdown
Contributor

What is the problem?

Users who want to run specialized bots (e.g. different personas, topic-focused assistants, or access-scoped bots) currently need separate gateway processes per bot. Each process has its own memory footprint (~200MB), its own config directory, and its own lifecycle management. This is operationally heavy for what is conceptually a single agent platform serving multiple front-ends.

Why this issue matters

A single gateway process already multiplexes Slack, Discord, Webex, and other channels. Telegram is the only channel locked to a 1:1 token:gateway ratio. Power users who want to expose different capabilities via different bot handles (e.g. a general assistant, a finance bot, and a domain-specific bot) are forced into N independent processes with duplicated config, duplicated memory, and no shared session management.

How the fix solves it

Adds telegram.accounts — a named map of bot accounts, each with its own bot_token, allowed_user_ids, and forum settings. One gateway starts one polling loop per account. Sessions are naturally isolated: named accounts use telegram:{account_id} as the channel namespace in the session key, while the default account keeps the bare telegram prefix for backward compatibility.

Agent routing: a new telegram_account field on the agent config binds an agent to a specific account. Messages on that bot route to the bound agent (workspace, memory store, model). Unbound accounts route to the default agent.

Backward compatible: when telegram.accounts is absent, the existing single-token config (telegram.bot_token) is auto-wrapped as a "default" account with zero behavioral change. Existing configs work unchanged.

The accounts config pattern is channel-agnostic by design and can be extended to Discord, Slack, and other channels in future PRs.

Config example

{
  "telegram": {
    "enabled": true,
    "accounts": {
      "main": { "bot_token": "...", "allowed_user_ids": [123] },
      "finance": { "bot_token": "...", "allowed_user_ids": [123, 456] }
    }
  },
  "agents": {
    "default": { "kiro_agent": "kirocrew", "workspace": "default", "telegram_account": "main" },
    "finance": { "kiro_agent": "kirocrew", "workspace": "finance", "telegram_account": "finance" }
  }
}

What tests we did

  • All 207 existing Telegram tests pass (zero regressions)
  • 9 new tests covering: config parsing, backward compat (single token wraps as default), explicit accounts taking precedence, session key isolation between accounts, agent binding
  • isort, flake8, mypy all clean
  • Manual verification that resolved_accounts() correctly synthesizes the legacy path

Other suggestions

  • Future PRs can extend the same accounts pattern to Discord (discord.accounts) and other channels with minimal effort — the session key builder already accepts arbitrary channel names.
  • Dashboard UI for managing multiple accounts (adding/removing tokens, viewing connected status per account) would be a natural follow-up.

@chenmingwei23
chenmingwei23 requested a review from a team as a code owner August 8, 2026 13:21
@github-actions github-actions Bot added readiness: checking Automated validation is still running merge conflict Branch has merge conflicts with its base — author must resolve before merge labels Aug 8, 2026
@chenmingwei23 chenmingwei23 reopened this Aug 8, 2026
@chenmingwei23
chenmingwei23 force-pushed the feat/multi-telegram-bot branch 2 times, most recently from 25a7235 to 4abb0e5 Compare August 8, 2026 14:28
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ human override accepted

Human judgment by @chenmingwei23 overrides the GPT 5.6 finding for 381d53bbe194577d814ac7a0001f48d850a77cfb; the recorded reason is authoritative for this commit.

This comment is updated in place on each push.

The model was not re-run because an authorized human decision supersedes it.

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 381d53bbe194577d814ac7a0001f48d850a77cfb: <one-sentence reason>

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — 🟡 CONCERNS

Advisory design-level review of 381d53bbe194577d814ac7a0001f48d850a77cfb — updated in place on each push; does not block merge.

Design-Verdict: CONCERNS

Named accounts ship half-integrated: an unregistered persisted session-key shape, silent per-account failures, and feature gaps all keyed on a magic "default" string.

Watch

  • New persisted key shape outside the registry. Named accounts mint telegram.{id}: session keys while CHANNEL_SESSION_NAMESPACES is untouched (the diff's own TODO admits it) → is_channel_session_key/parse_session_key reject them → no dashboard chat slots, telemetry "other", no autonudge. Once these keys are persisted to history, later registering the namespace or changing the separator needs a data migration — this is the PR's one-way door and it ships as a TODO rather than a decision.
  • Non-default accounts fail invisibly. telegram_connected / telegram_connect_error and status callbacks are set only if account_id == "default", and _parse_telegram_accounts silently drops malformed entries → a revoked token or typo on the second bot leaves it dead with only a log line, in a feature whose entire purpose is running several bots. No per-account health surface = no failure story on the fallible path.
  • Inverted binding allows ambiguity. Routing scans agents.* for telegram_account == account_id; two agents naming the same account resolve by dict insertion order, silently. accounts.<id>.agent would make the one-to-one relation structural — and the "channel-agnostic pattern" claim doesn't hold when each future channel needs its own agent-config field.
  • Phantom per-account knob. TelegramAccountConfig.soft_threshold_pct is parsed and documented per-account, but the dispatcher still reads the global cfg.telegram.soft_threshold_pct — dead config surface that's hard to retract once users set it. Also: config schema and session-key behavior changed with no docs/system-specs/modules/messaging.md update in the commit.

Suggestions

  • Register telegram.{id} (or pick the final key grammar) in CHANNEL_SESSION_NAMESPACES in this PR, before the first named-account session is persisted — it's a data change per the spec, not a follow-up.
  • Move the binding to accounts.<id>.agent and drop telegram_account from agent config before this becomes public schema.

[DESIGN-REVIEWED] 381d53b

@chenmingwei23
chenmingwei23 force-pushed the feat/multi-telegram-bot branch from 4abb0e5 to 773a614 Compare August 8, 2026 14:44
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention merge conflict Branch has merge conflicts with its base — author must resolve before merge readiness: checking Automated validation is still running labels Aug 8, 2026
@chenmingwei23

Copy link
Copy Markdown
Contributor Author

/ai-review override gpt 773a614: accounts.bot_token has identical security posture as the existing telegram.bot_token field (also in config.json with the same sensitive=True metadata). The field exists for convenience alongside the recommended .env path, matching the established pattern.

@chenmingwei23
chenmingwei23 force-pushed the feat/multi-telegram-bot branch from 773a614 to 7aa8c03 Compare August 8, 2026 14:56
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

AI-review override not recorded: 773a614221a1b380c17b41f393d1a016ebd8379b is not the current PR head. Re-run the command with 7aa8c0327ed5e7e5207175b4120b8d7bc7caa03d.

@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 8, 2026
Add telegram.accounts config map enabling a single gateway process to
serve multiple Telegram bots simultaneously. Each named account has its
own bot_token, allowed_user_ids, and forum settings. Messages on each
account are routed to a bound agent (via the new telegram_account field
on KiroCrewAgentConfig), with session keys naturally isolated by
incorporating the account ID into the channel namespace.

Backward compatible: when telegram.accounts is absent, the existing
single-token config is auto-wrapped as a 'default' account with no
behavioral change. The accounts config pattern is channel-agnostic by
design and can be extended to Discord, Slack, and other channels in
future PRs.

Config schema:
  telegram.accounts.{name}.bot_token
  telegram.accounts.{name}.allowed_user_ids
  telegram.accounts.{name}.allow_forum
  telegram.accounts.{name}.allowed_forum_chat_ids
  agents.{name}.telegram_account (binds agent to account)
@chenmingwei23
chenmingwei23 force-pushed the feat/multi-telegram-bot branch from 7aa8c03 to 381d53b Compare August 8, 2026 15:08
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 8, 2026
@chenmingwei23

Copy link
Copy Markdown
Contributor Author

/ai-review override gpt 381d53b: The field carries sensitive=True metadata (line 3840), which is the same mechanism the existing telegram.bot_token uses for masking in the /api/config response. Dynamic-path masking for nested fields is a config-API concern orthogonal to this PR.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@chenmingwei23 marked the gpt AI finding as false positive, not applicable, or explicitly accepted for 381d53bbe194577d814ac7a0001f48d850a77cfb.

The field carries sensitive=True metadata (line 3840), which is the same mechanism the existing telegram.bot_token uses for masking in the /api/config response. Dynamic-path masking for nested fields is a config-API concern orthogonal to this PR.

This decision applies only to this commit. A new push requires a new judgment.

@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Opus 5 Review — ✅ no blocking findings

Reviewed 381d53bbe194577d814ac7a0001f48d850a77cfb — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 381d53b

Verdict parsed from the review's SHA-scoped output markers for commit 381d53bbe194577d814ac7a0001f48d850a77cfb.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 381d53bbe194577d814ac7a0001f48d850a77cfb: <one-sentence reason>

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Aug 8, 2026
@chenmingwei23
chenmingwei23 enabled auto-merge (squash) August 8, 2026 15:51

@iamwhatever iamwhatever left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This one definitely require additional control configured, specifically governance management. Please check the way to turn this one off with simple config as the enterprise may not want this thing for security reason.

@chenmingwei23
chenmingwei23 merged commit 53a2ec1 into main Aug 9, 2026
48 of 49 checks passed
@chenmingwei23
chenmingwei23 deleted the feat/multi-telegram-bot branch August 9, 2026 08:43
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Aug 9, 2026
bolichen97 added a commit that referenced this pull request Aug 9, 2026
)

The 0.2.0 section was written in #2305, the commit that became v0.2.0-rc.4.
Seventy-one commits have landed on main since, nineteen of them feat:, and
the section was never revisited. It therefore both omitted shipped features
and described one that no longer exists as written.

The wrong entry mattered most: the Webhooks bullet told the reader to manage
inbound automation "from Settings", but #2343 moved that page behind a
per-device Preview pages toggle under Developer and hides it by default. A
0.2.0 user following the release notes would have gone looking for a page
that is not there.

Added, all from the rc.6 range: opt-in Slack setup and the multi-channel
repositioning (#2340), Telegram multi-account (#2203) and inbound
attachments (#2201), sub-agent completions reaching non-Slack parents
(#2352), Discord reply continuation (#2326), Slack OPTIONS as a control
(#1467), the Agent Templates two-pane inspector, project-local agent
discovery (#2167), send-a-copy-to-another-instance, Jira and setting link
chips (#2019, #1907), CJK emphasis rendering, the MCP Apps switch (#2293,
#2337), the Connections provider registry (#2285), GitHub Enterprise
Server support in Code Review Sage (#2154), operator notes on user deny
patterns (#2341), the locked git-publish floor rules (#2369), the
persist-or-refuse boot guard (#2279), and the turn-ceiling bounds on the
approval and stall windows (#2372, #2373).

Scope is exactly 5fe4bd5..ab20b4e, the range v0.2.0-rc.6 ships. The
three commits main carries beyond rc.6, including meeting deletion (#2268),
belong to the next release and are deliberately not described here.
encomjp pushed a commit to encomjp/kirocrew-customapi that referenced this pull request Aug 22, 2026
…#2203)

Add telegram.accounts config map enabling a single gateway process to
serve multiple Telegram bots simultaneously. Each named account has its
own bot_token, allowed_user_ids, and forum settings. Messages on each
account are routed to a bound agent (via the new telegram_account field
on KiroCrewAgentConfig), with session keys naturally isolated by
incorporating the account ID into the channel namespace.

Backward compatible: when telegram.accounts is absent, the existing
single-token config is auto-wrapped as a 'default' account with no
behavioral change. The accounts config pattern is channel-agnostic by
design and can be extended to Discord, Slack, and other channels in
future PRs.

Config schema:
  telegram.accounts.{name}.bot_token
  telegram.accounts.{name}.allowed_user_ids
  telegram.accounts.{name}.allow_forum
  telegram.accounts.{name}.allowed_forum_chat_ids
  agents.{name}.telegram_account (binds agent to account)
encomjp pushed a commit to encomjp/kirocrew-customapi that referenced this pull request Aug 22, 2026
…rodotdev#2412)

The 0.2.0 section was written in kirodotdev#2305, the commit that became v0.2.0-rc.4.
Seventy-one commits have landed on main since, nineteen of them feat:, and
the section was never revisited. It therefore both omitted shipped features
and described one that no longer exists as written.

The wrong entry mattered most: the Webhooks bullet told the reader to manage
inbound automation "from Settings", but kirodotdev#2343 moved that page behind a
per-device Preview pages toggle under Developer and hides it by default. A
0.2.0 user following the release notes would have gone looking for a page
that is not there.

Added, all from the rc.6 range: opt-in Slack setup and the multi-channel
repositioning (kirodotdev#2340), Telegram multi-account (kirodotdev#2203) and inbound
attachments (kirodotdev#2201), sub-agent completions reaching non-Slack parents
(kirodotdev#2352), Discord reply continuation (kirodotdev#2326), Slack OPTIONS as a control
(kirodotdev#1467), the Agent Templates two-pane inspector, project-local agent
discovery (kirodotdev#2167), send-a-copy-to-another-instance, Jira and setting link
chips (kirodotdev#2019, kirodotdev#1907), CJK emphasis rendering, the MCP Apps switch (kirodotdev#2293,
kirodotdev#2337), the Connections provider registry (kirodotdev#2285), GitHub Enterprise
Server support in Code Review Sage (kirodotdev#2154), operator notes on user deny
patterns (kirodotdev#2341), the locked git-publish floor rules (kirodotdev#2369), the
persist-or-refuse boot guard (kirodotdev#2279), and the turn-ceiling bounds on the
approval and stall windows (kirodotdev#2372, kirodotdev#2373).

Scope is exactly 5fe4bd5..ab20b4e, the range v0.2.0-rc.6 ships. The
three commits main carries beyond rc.6, including meeting deletion (kirodotdev#2268),
belong to the next release and are deliberately not described here.
encomjp pushed a commit to encomjp/kirocrew-customapi that referenced this pull request Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants