qwen-code/packages/channels/base/src/GroupGate.ts
tanzhenxin 90236465d3 feat(channels): add group chat support for Telegram
- Add GroupGate class for group access control with three policies:
  disabled (default), allowlist, and open
- Implement mention gating: bot only responds when @mentioned or replied to
  in groups (configurable per-group)
- Extend Envelope type with isGroup, isMentioned, isReplyToBot fields
- Update TelegramAdapter to detect group context and mentions
- Add comprehensive documentation for group chat setup and troubleshooting

This enables using Qwen Code bots in Telegram groups with fine-grained
access control and mention-based activation to prevent noise.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-25 02:04:27 +00:00

57 lines
1.7 KiB
TypeScript

import type { GroupPolicy, GroupConfig, Envelope } from './types.js';
export interface GroupCheckResult {
allowed: boolean;
reason?: 'disabled' | 'not_allowlisted' | 'mention_required';
}
export class GroupGate {
private policy: GroupPolicy;
private groups: Record<string, GroupConfig>;
constructor(
policy: GroupPolicy = 'disabled',
groups: Record<string, GroupConfig> = {},
) {
this.policy = policy;
this.groups = groups;
}
/**
* Full group check: policy + allowlist + mention gating.
* Evaluation order:
* 1. groupPolicy (disabled → drop)
* 2. group allowlist (allowlist mode, no match → drop)
* 3. mention gating (requireMention + not mentioned → drop silently)
*
* Mention gating runs before sender gate so that unmentioned messages
* in groups don't trigger pairing flows.
*/
check(envelope: Envelope): GroupCheckResult {
if (!envelope.isGroup) {
return { allowed: true };
}
if (this.policy === 'disabled') {
return { allowed: false, reason: 'disabled' };
}
if (this.policy === 'allowlist') {
// In allowlist mode, "*" is only a default config — not a wildcard allow.
// The group must be explicitly listed by ID.
if (!this.groups[envelope.chatId]) {
return { allowed: false, reason: 'not_allowlisted' };
}
}
// Per-group config, falling back to "*" defaults, then built-in defaults
const groupConfig = this.groups[envelope.chatId] || this.groups['*'] || {};
const requireMention = groupConfig.requireMention ?? true;
if (requireMention && !envelope.isMentioned && !envelope.isReplyToBot) {
return { allowed: false, reason: 'mention_required' };
}
return { allowed: true };
}
}