#5972

Telegram: per-chat and per-topic group policy (and a /group command to manage it)

OpenCarmeloCamposopened 1mo ago

Feature Request

Telegram's groupPolicy is channel-wide ("open" or "mention"), so a single bot serving a busy supergroup has one behavior everywhere. With forum topics, that becomes a real limitation: a team group usually wants the bot to take part in project topics, but stay silent in announcement/tracking topics — and today that is impossible, because the policy applies to the whole chat at once.

Napcat already solved the equivalent problem per group, so this looks like a gap in Telegram rather than an intentional difference:

# nanobot/channels/napcat/runtime.py
group_policy_overrides: dict[str, GroupPolicy] = Field(default_factory=dict)

policy = self.config.group_policy_overrides.get(str(group_id), self.config.group_policy)

This request is to bring that same capability to Telegram, adapted to its topic model.

The Telegram-specific wrinkle

Telegram forum topics do not have their own chat id. Every topic in a supergroup shares the parent chat_id and is distinguished only by message_thread_id. So a group-scoped key like Napcat's str(group_id) cannot express "one topic". The key needs both parts.

Proposed Design

1. Config overrides

{
  "channels": {
    "telegram": {
      "groupPolicy": "open",
      "groupPolicyOverrides": {
        "-1001668715626": "open",
        "-1001668715626:7819": "mention"
      }
    }
  }
}
  • "<chat_id>" — applies to a whole chat.
  • "<chat_id>:<thread_id>" — applies to one forum topic; most specific match wins.
  • Unlisted scopes fall back to groupPolicy.

This needs no new enum value: with the channel policy at "open", giving a topic "mention" already means "don't jump into the conversation, but answer if called" — which is exactly the usual intent for a muted topic. Keeping the value set at {mention, open} keeps the change small.

2. Manage it from chat

Editing JSON and restarting the gateway is a poor fit for "this topic is noisy right now". A command makes it self-service from the chat where the problem is:

/group              → show the effective policy for this chat/topic
/group mention      → only reply here when mentioned
/group open         → reply to every message here
/group reset        → clear the override for this chat/topic

The command is scoped to the calling chat/topic, so it never needs a raw thread id from the user.

Runtime overrides should layer on top of the static config rather than replace it, so durable policy can stay in config.json while /group handles exceptions:

  1. runtime topic override
  2. runtime chat override
  3. static topic override (config.json)
  4. static chat override (config.json)
  5. channel-wide groupPolicy

Scopes should be keyed by channel too (telegram:<chat_id>[:<thread_id>]), so Telegram and Discord overrides cannot collide.

Suggested Scope

Two PRs, since they are independently useful and reviewable:

  1. groupPolicyOverrides config support + Telegram resolution.
  2. The /group command backed by a small runtime store, layering over (1).

A PR for (1) is up as #5972. I have (2) ready to open on top of it.

Alternatives Considered

  • Reusing allowFrom / groupAllowFrom: those gate who may talk, not when the bot answers. Slack's groupRequireMention is closer but still not per-scope.
  • Making the topic list an allowlist-only feature (groupPolicy: "allowlist"): would need a new policy value and still could not express "open here, mention there, in one chat".
  • Editing config.json from the command: nanobot refreshes agent runtime config on file change, but channels read their config at construction, so it would not take effect without a restart. A separate runtime store avoids that coupling.

Environment

  • nanobot 0.3.5 (main @ 3cf6ed6)
  • Use case: team Telegram supergroup with per-topic behavior

Activity

0

No activity yet.