feat(telegram): add topic name support for forum topics

- Add 'name' field to TelegramTopicConfig for human-readable topic names
- Update buildGroupLabel to display topic name instead of just ID when configured
- Add TopicName field to MsgContext for agent visibility
- Update Zod schema for config validation

This allows users to configure meaningful names for Telegram forum topics:

channels:
  telegram:
    groups:
      "-1234567890":
        topics:
          "37":
            name: "General Discussion"

The agent will now see 'topic:General Discussion' instead of 'topic:37' in the
conversation context.
This commit is contained in:
Walter 2026-01-30 12:55:13 +08:00
parent 4de0bae45a
commit 88995f3c5d
5 changed files with 18 additions and 2 deletions

View File

@ -103,6 +103,8 @@ export type MsgContext = {
CommandTargetSessionKey?: string; CommandTargetSessionKey?: string;
/** Thread identifier (Telegram topic id or Matrix thread event id). */ /** Thread identifier (Telegram topic id or Matrix thread event id). */
MessageThreadId?: string | number; MessageThreadId?: string | number;
/** Topic name from config (Telegram forum topics). */
TopicName?: string;
/** Telegram forum supergroup marker. */ /** Telegram forum supergroup marker. */
IsForum?: boolean; IsForum?: boolean;
/** /**

View File

@ -133,6 +133,8 @@ export type TelegramAccountConfig = {
}; };
export type TelegramTopicConfig = { export type TelegramTopicConfig = {
/** Human-readable name for this topic (displayed in conversation context). */
name?: string;
requireMention?: boolean; requireMention?: boolean;
/** If specified, only load these skills for this topic. Omit = all skills; empty = no skills. */ /** If specified, only load these skills for this topic. Omit = all skills; empty = no skills. */
skills?: string[]; skills?: string[];

View File

@ -37,6 +37,7 @@ const TelegramCapabilitiesSchema = z.union([
export const TelegramTopicSchema = z export const TelegramTopicSchema = z
.object({ .object({
name: z.string().optional(),
requireMention: z.boolean().optional(), requireMention: z.boolean().optional(),
skills: z.array(z.string()).optional(), skills: z.array(z.string()).optional(),
enabled: z.boolean().optional(), enabled: z.boolean().optional(),

View File

@ -495,7 +495,9 @@ export const buildTelegramMessageContext = async ({
forwardOrigin.date ? ` at ${new Date(forwardOrigin.date * 1000).toISOString()}` : "" forwardOrigin.date ? ` at ${new Date(forwardOrigin.date * 1000).toISOString()}` : ""
}]\n` }]\n`
: ""; : "";
const groupLabel = isGroup ? buildGroupLabel(msg, chatId, resolvedThreadId) : undefined; const groupLabel = isGroup
? buildGroupLabel(msg, chatId, resolvedThreadId, topicConfig?.name)
: undefined;
const senderName = buildSenderName(msg); const senderName = buildSenderName(msg);
const conversationLabel = isGroup const conversationLabel = isGroup
? (groupLabel ?? `group:${chatId}`) ? (groupLabel ?? `group:${chatId}`)
@ -605,6 +607,8 @@ export const buildTelegramMessageContext = async ({
CommandAuthorized: commandAuthorized, CommandAuthorized: commandAuthorized,
// For groups: use resolvedThreadId (forum topics only); for DMs: use raw messageThreadId // For groups: use resolvedThreadId (forum topics only); for DMs: use raw messageThreadId
MessageThreadId: isGroup ? resolvedThreadId : messageThreadId, MessageThreadId: isGroup ? resolvedThreadId : messageThreadId,
// Topic name from config (if configured)
TopicName: isGroup && resolvedThreadId != null ? topicConfig?.name : undefined,
IsForum: isForum, IsForum: isForum,
// Originating channel for reply routing. // Originating channel for reply routing.
OriginatingChannel: "telegram" as const, OriginatingChannel: "telegram" as const,

View File

@ -106,9 +106,16 @@ export function buildGroupLabel(
msg: TelegramMessage, msg: TelegramMessage,
chatId: number | string, chatId: number | string,
messageThreadId?: number, messageThreadId?: number,
topicName?: string,
) { ) {
const title = msg.chat?.title; const title = msg.chat?.title;
const topicSuffix = messageThreadId != null ? ` topic:${messageThreadId}` : ""; // Include topic name if available, otherwise just show topic ID
const topicSuffix =
messageThreadId != null
? topicName
? ` topic:${topicName}`
: ` topic:${messageThreadId}`
: "";
if (title) return `${title} id:${chatId}${topicSuffix}`; if (title) return `${title} id:${chatId}${topicSuffix}`;
return `group:${chatId}${topicSuffix}`; return `group:${chatId}${topicSuffix}`;
} }