hermes - ✅(Solved) Fix [Bug]: `channel_prompts` keys collide across supergroups when using forum topic thread_ids [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

channel_prompts uses thread_id as a flat string key, but Telegram forum topic thread_ids are small integers (1, 4, 5, 6...) that are unique only within a single supergroup. When a bot is an admin in multiple supergroups, the same thread_id value appears in different groups, causing the wrong channel_prompt to be injected.

Error Message

Additional Logs / Traceback (optional)

Root Cause

Both topics receive the same channel_prompt because the key "5" matches any message with thread_id=5, regardless of which supergroup it originates from.

Fix Action

Workaround

Use group-level chat_id keys instead of topic-level thread_id keys. This provides per-supergroup context but not per-topic context:

channel_prompts: "-1001111111111": | This is the construction group. All topics here relate to villa projects. "-1002222222222": | This is the software group. All topics here relate to code projects.

PR fix notes

PR #13272: fix(gateway): disambiguate channel_prompts across parents (#13256)

Description (problem / solution / changelog)

Closes #13256.

Problem

channel_prompts keys are looked up as flat strings. Telegram forum thread_ids are small ints scoped to a single supergroup (the General topic is always 1), so a bare "1" key matches the General topic of every supergroup the bot is in. A typical 5-supergroup setup has pervasive collisions at thread_id=1, plus incidental collisions at small ids like 5, 6.

Fix

Extend resolve_channel_prompt in gateway/platforms/base.py to accept composite {parent_id}:{channel_id} keys, tried before the existing channel_id and parent_id lookups:

telegram:
  channel_prompts:
    "-1001234567890:42": Invoices topic in Group A.
    "-1009876543210:42": Backend topic in Group B.
    "-1001234567890":    Group A fallback.
    "42":                Generic topic-42 fallback.

The composite is only constructed when both parent_id and channel_id are truthy, so adapters that don't pass a parent (Slack, Mattermost, Discord non-thread) are unaffected. Existing flat configs keep working — the new key is strictly additive.

The : separator and parent-first ordering match the de facto convention already used in gateway/channel_directory.py, gateway/delivery.py, and several adapters.

Test plan

  • uv run pytest tests/gateway/test_platform_base.py::TestResolveChannelPromptComposite — 8 new tests cover composite match, collision disambiguation (the #13256 repro), precedence over both flat-key forms, backward-compat fall-through, composite-not-constructed-without-parent, and blank-value fall-through.
  • uv run pytest tests/gateway/test_discord_channel_prompts.py — 10 existing tests still pass; verifies backward compat across the Discord adapter path.
  • Docs updated in website/docs/user-guide/messaging/telegram.md to describe the composite key syntax in the existing Per-Channel Prompts section.

Changed files

  • gateway/platforms/base.py (modified, +6/-9)
  • tests/gateway/test_platform_base.py (modified, +63/-0)
  • website/docs/user-guide/messaging/telegram.md (modified, +13/-0)

Code Example

platforms:
  telegram:
    extra:
      group_topics:
        - chat_id: -1001111111111           # Group A: "construction"
          topics:
            - name: invoices
              thread_id: 5
              skill: construction-management
        - chat_id: -1002222222222           # Group B: "software"
          topics:
            - name: backend
              thread_id: 5
              skill: software-development
    channel_prompts:
      # BUG: both topics have thread_id 5 — only one prompt can exist
      "5": |
        ???  # Which project does this apply to?

---

## Suggested Fix

Support composite keys in `channel_prompts` that include the `chat_id`:


channel_prompts:
  "-1001111111111": |          # group-level (existing, works fine)
    Default prompt for Group A.
  "-1001111111111:5": |        # NEW: chat_id:thread_id composite key
    Invoices topic in Group A.
  "-1002222222222:5": |        # NEW: disambiguated
    Backend topic in Group B.
  "5": |                       # EXISTING: fallback for unscoped thread_id
    Generic prompt for any topic 5.


**Resolution order (most specific wins):**
1. `chat_id:thread_id` — exact match
2. `thread_id` — topic-level fallback (current behavior)
3. `chat_id` — group-level fallback (current behavior)

This is backward-compatible — existing configs without composite keys continue to work. The `group_topics` structure already uses this `(chat_id, thread_id)` tuple for skill binding, so extending `channel_prompts` to match is consistent.

## Related Issues

- #4431Proposes `topic_configs` with `platform:chat_id:thread_id` composite key (community patch exists, not merged)
- #5195Requests per-topic SOUL.md binding via `group_topics` sub-configuration

## Workaround

Use group-level `chat_id` keys instead of topic-level `thread_id` keys. This provides per-supergroup context but not per-topic context:


channel_prompts:
  "-1001111111111": |
    This is the construction group. All topics here relate to villa projects.
  "-1002222222222": |
    This is the software group. All topics here relate to code projects.

---
RAW_BUFFERClick to expand / collapse

Bug Description

Summary

channel_prompts uses thread_id as a flat string key, but Telegram forum topic thread_ids are small integers (1, 4, 5, 6...) that are unique only within a single supergroup. When a bot is an admin in multiple supergroups, the same thread_id value appears in different groups, causing the wrong channel_prompt to be injected.

Environment

  • Hermes Agent v0.10.x
  • Telegram gateway with group_topics across multiple supergroups
  • Single profile bot as admin in 3+ supergroups with forum topics enabled

Steps to Reproduce

Steps to Reproduce

  1. Create two supergroups with forum topics enabled
  2. Create topics in each group — Telegram assigns small integer thread_ids starting from low numbers
  3. Configure a single Hermes profile with group_topics for both supergroups
  4. Add channel_prompts with topic-level thread_id keys

Config:

platforms:
  telegram:
    extra:
      group_topics:
        - chat_id: -1001111111111           # Group A: "construction"
          topics:
            - name: invoices
              thread_id: 5
              skill: construction-management
        - chat_id: -1002222222222           # Group B: "software"
          topics:
            - name: backend
              thread_id: 5
              skill: software-development
    channel_prompts:
      # BUG: both topics have thread_id 5 — only one prompt can exist
      "5": |
        ???  # Which project does this apply to?
  1. Send a message in Group A's "invoices" topic (thread_id 5)
  2. Send a message in Group B's "backend" topic (thread_id 5)

Expected Behavior

Expected Behavior

Each topic should receive its own context-specific prompt. The group_topics config already disambiguates correctly by (chat_id, thread_id)channel_prompts should support the same scoping.

Actual Behavior

Actual Behavior

Both topics receive the same channel_prompt because the key "5" matches any message with thread_id=5, regardless of which supergroup it originates from.

The collision is especially severe for thread_id: 1 (General topic), which exists in every supergroup with forum topics enabled.

Scope of Impact

A typical multi-group setup has pervasive collisions. Example with 5 supergroups:

thread_idAppears in
1All 5 groups (General topic)
53 groups
62 groups

This makes per-topic channel_prompts unsafe for any bot that operates across multiple supergroups.

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp)

Messaging Platform (if gateway-related)

No response

Debug Report

## Suggested Fix

Support composite keys in `channel_prompts` that include the `chat_id`:


channel_prompts:
  "-1001111111111": |          # group-level (existing, works fine)
    Default prompt for Group A.
  "-1001111111111:5": |        # NEW: chat_id:thread_id composite key
    Invoices topic in Group A.
  "-1002222222222:5": |        # NEW: disambiguated
    Backend topic in Group B.
  "5": |                       # EXISTING: fallback for unscoped thread_id
    Generic prompt for any topic 5.


**Resolution order (most specific wins):**
1. `chat_id:thread_id` — exact match
2. `thread_id` — topic-level fallback (current behavior)
3. `chat_id` — group-level fallback (current behavior)

This is backward-compatible — existing configs without composite keys continue to work. The `group_topics` structure already uses this `(chat_id, thread_id)` tuple for skill binding, so extending `channel_prompts` to match is consistent.

## Related Issues

- #4431 — Proposes `topic_configs` with `platform:chat_id:thread_id` composite key (community patch exists, not merged)
- #5195 — Requests per-topic SOUL.md binding via `group_topics` sub-configuration

## Workaround

Use group-level `chat_id` keys instead of topic-level `thread_id` keys. This provides per-supergroup context but not per-topic context:


channel_prompts:
  "-1001111111111": |
    This is the construction group. All topics here relate to villa projects.
  "-1002222222222": |
    This is the software group. All topics here relate to code projects.

Operating System

Ubuntu

Python Version

No response

Hermes Version

No response

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

No response

Proposed Fix (optional)

No response

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

extent analysis

TL;DR

Support composite keys in channel_prompts that include the chat_id to disambiguate thread IDs across multiple supergroups.

Guidance

  • Update the channel_prompts configuration to use composite keys in the format chat_id:thread_id to uniquely identify topics across different supergroups.
  • Ensure the resolution order is correctly implemented, with the most specific key (chat_id:thread_id) taking precedence over less specific keys (thread_id or chat_id alone).
  • Test the updated configuration with multiple supergroups and topics to verify that the correct prompts are being displayed.
  • Consider implementing a fallback mechanism to handle cases where the composite key is not provided, using the existing thread_id or chat_id keys as a fallback.

Example

channel_prompts:
  "-1001111111111:5": |
    Invoices topic in Group A.
  "-1002222222222:5": |
    Backend topic in Group B.

Notes

The proposed fix requires updating the channel_prompts configuration to support composite keys, which may require changes to the underlying code or configuration parsing logic. Additionally, the resolution order and fallback mechanism should be carefully implemented to ensure correct behavior in all scenarios.

Recommendation

Apply the workaround by using composite keys in the channel_prompts configuration, as this provides a clear and consistent way to disambiguate thread IDs across multiple supergroups. This approach is also backward-compatible with existing configurations.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix [Bug]: `channel_prompts` keys collide across supergroups when using forum topic thread_ids [1 pull requests]