消息平台
Telegram
已通过 grammY 达到生产就绪状态,支持 Bot 私信和群组。默认传输方式为长轮询;也可选择 webhook 模式。
快速设置
在 BotFather 中创建 Bot 令牌
以下两种流程最终都会生成一个可粘贴到 OpenClaw 中的令牌,可任选一种:
- 聊天流程:打开 Telegram,与 @BotFather 聊天(确认用户名正是
@BotFather),运行/newbot,按照提示操作并保存令牌。 - 网页流程:打开 BotFather 的 Web 应用——它可在所有 Telegram 客户端中运行,包括 web.telegram.org——在界面中创建 Bot,并复制其令牌。
配置令牌和私信策略
{channels: {telegram: { enabled: true, botToken: "123:abc", dmPolicy: "pairing", groups: { "*": { requireMention: true } },},},}环境变量回退:TELEGRAM_BOT_TOKEN(仅限默认账户;命名账户必须使用 botToken 或 tokenFile)。
Telegram 不使用 openclaw channels login telegram;请在配置或环境变量中设置令牌,然后启动 Gateway 网关。
启动 Gateway 网关并批准第一条私信
openclaw gatewayopenclaw pairing list telegramopenclaw pairing approve telegram <CODE>配对码将在 1 小时后过期。
将 Bot 添加到群组
将 Bot 添加到你的群组,然后获取群组访问所需的两个 ID:
- 你的 Telegram 用户 ID,用于
allowFrom/groupAllowFrom - Telegram 群聊 ID,作为
channels.telegram.groups下的键
可通过 openclaw logs --follow、转发消息获取 ID 的 Bot 或 Bot API getUpdates 获取群聊 ID。允许该群组后,/whoami@<bot_username> 可确认用户 ID 和群组 ID。
以 -100 开头的负数超级群组 ID 是群聊 ID。它们应放在 channels.telegram.groups 下,而不是 groupAllowFrom 中。
Telegram 端设置
隐私模式和群组可见性
Telegram Bot 默认启用 Privacy Mode,这会限制它们能够接收的群组消息。
要查看所有群组消息,可采用以下任一方式:
- 通过
/setprivacy禁用隐私模式,或 - 将 Bot 设为群组管理员。
切换隐私模式后,请在每个群组中移除并重新添加 Bot,以便 Telegram 应用更改。
群组权限
管理员状态在 Telegram 群组设置中控制。管理员 Bot 会接收所有群组消息,这对于始终启用群组行为很有用。
实用的 BotFather 开关
/setjoingroups— 允许/拒绝添加到群组/setprivacy— 群组可见性行为
如果你更喜欢使用 UI 而不是聊天命令,也可以在 BotFather 的 Web 应用中使用相同的设置。
仪表板 Mini App
在与机器人的私信中运行 /dashboard,即可在 Telegram 内打开 OpenClaw 仪表板。
要求:
gateway.tailscale.mode: "serve"或"funnel",用于已发布的 HTTPS Mini App URL。- 你的 Telegram 数字用户 ID 必须位于所选账号的有效
allowFrom中,或位于commands.ownerAllowFrom中。 - 使用私信。在群组中,
/dashboard会回复open this in a DM with the bot,且不发送按钮。 - Docker 安装:Serve/Funnel 模式要求 Gateway 网关在
tailscaled旁绑定到环回地址,而使用已发布端口的桥接网络无法满足此要求。使用network_mode: host运行 Gateway 网关容器,并将主机的tailscaled套接字(/var/run/tailscale)以及tailscaleCLI 挂载到容器中。
Mini App 是仅限 Tailscale 的 v1 路径,不支持 Telegram Web iframe。
访问控制和激活
群组 Bot 身份
在群组和论坛话题中,明确提及已配置的 Bot 用户名(例如 @my_bot)就是在呼叫所选的 OpenClaw 智能体,即使智能体角色名称与 Telegram 用户名不同。群组静默策略仍适用于无关消息,但 Bot 用户名本身绝不会被视为“其他人”。
私信策略
channels.telegram.dmPolicy 控制私信访问:
pairing(默认)allowlist(要求allowFrom中至少包含一个发送者 ID)open(要求allowFrom包含"*")disabled
使用 dmPolicy: "open" 和 allowFrom: ["*"] 后,任何找到或猜出 Bot 用户名的 Telegram 账号都可以向 Bot 发出命令。仅应将其用于有意公开且严格限制工具的 Bot;单一所有者 Bot 应使用包含数字用户 ID 的 allowlist。
channels.telegram.allowFrom 接受数字形式的 Telegram 用户 ID。支持 telegram: / tg: 前缀,并会进行规范化。
在多账号配置中,限制性的顶层 channels.telegram.allowFrom 是一道安全边界:账号级 allowFrom: ["*"] 不会使该账号公开,除非合并后的有效允许列表仍包含显式通配符。
dmPolicy: "allowlist" 搭配空的 allowFrom 会阻止所有私信,并会被配置验证拒绝。
设置流程仅要求数字用户 ID。如果你的配置包含旧版设置留下的 @username 允许列表条目,请运行 openclaw doctor --fix,将其解析为数字 ID(尽力而为;需要 Telegram Bot 令牌)。
如果你之前依赖配对存储的允许列表文件,openclaw doctor --fix 可以为允许列表流程将其中的条目恢复到 channels.telegram.allowFrom(例如,当 dmPolicy: "allowlist" 尚未包含显式 ID 时)。
对于单一所有者 Bot,建议使用 dmPolicy: "allowlist" 并在 allowFrom 中明确指定数字 ID,而不是依赖之前的配对批准。
常见误解:批准私信配对并不意味着“此发送者在所有地方都已获得授权”。配对仅授予私信访问权限。如果尚不存在命令所有者,首次获批的配对还会设置 commands.ownerAllowFrom,从而为仅所有者可用的命令和 Exec 审批指定明确的操作员账号。群组发送者授权仍来自显式配置的允许列表。
要让同一身份同时获得私信和群组命令授权:请将你的数字 Telegram 用户 ID 放入 channels.telegram.allowFrom;对于仅所有者可用的命令,请确保 commands.ownerAllowFrom 包含 telegram:<your user id>。
查找你的 Telegram 用户 ID
更安全(无需第三方 Bot):向你的 Bot 发送私信,运行 openclaw logs --follow,查看 from.id。
官方 Bot API 方法:
curl "https://api.telegram.org/bot<bot_token>/getUpdates"第三方方式(隐私性较低):@userinfobot 或 @getidsbot。
群组策略和允许列表
以下两项控制同时生效:
-
允许哪些群组(
channels.telegram.groups)- 未配置
groups,且groupPolicy: "open":任何群组都可通过群组 ID 检查 - 未配置
groups,且groupPolicy: "allowlist"(默认):在添加groups条目(或"*")之前阻止所有群组 - 已配置
groups:作为允许列表使用(显式 ID 或"*")
- 未配置
-
群组中允许哪些发送者(
channels.telegram.groupPolicy)open/allowlist(默认)/disabled
groupAllowFrom 用于筛选群组发送者;如果未设置,Telegram 会回退到 allowFrom(而非配对存储——群组发送者身份验证绝不会继承私信配对存储的批准,这是自 2026.2.25 起设立的安全边界)。
groupAllowFrom 条目应为数字形式的 Telegram 用户 ID(telegram: / tg: 前缀会被规范化);非数字条目会被忽略。不要在此处填写群组或超级群组聊天 ID——负数聊天 ID 应放在 channels.telegram.groups 下。
单一所有者 Bot 的实用配置方式:在 channels.telegram.allowFrom 中设置你的用户 ID,不设置 groupAllowFrom,并在 channels.telegram.groups 下允许目标群组。
如果配置中完全没有 channels.telegram,除非显式设置了 channels.defaults.groupPolicy,否则运行时默认采用故障关闭的 groupPolicy="allowlist"。
仅所有者可用的群组设置:
{channels: {telegram: { enabled: true, dmPolicy: "pairing", allowFrom: ["<YOUR_TELEGRAM_USER_ID>"], groupPolicy: "allowlist", groups: { "<GROUP_CHAT_ID>": { requireMention: true, }, },},},}在群组中使用 @<bot_username> ping 进行测试。当 requireMention: true 时,普通群组消息不会触发 Bot。
允许某个特定群组中的所有成员:
{channels: {telegram: { groups: { "-1001234567890": { groupPolicy: "open", requireMention: false, }, },},},}仅允许某个特定群组中的指定用户:
{channels: {telegram: { groups: { "-1001234567890": { requireMention: true, allowFrom: ["8734062810", "745123456"], }, },},},}提及行为
默认情况下,群组回复需要提及 Bot。提及可以来自:
- 原生
@botusername提及,或 agents.list[].groupChat.mentionPatterns或messages.groupChat.mentionPatterns中的提及模式
会话级切换(仅影响状态,不持久化):/activation always、/activation mention。如需持久化,请使用配置:
{channels: {telegram: { groups: { "*": { requireMention: false }, },},},}群组历史上下文始终启用,并受 historyLimit 限制。设置 channels.telegram.historyLimit: 0 可禁用群组历史窗口。openclaw doctor --fix 会删除已停用的 includeGroupHistoryContext 键。
获取群组聊天 ID:将群组消息转发给 @userinfobot / @getidsbot,从 openclaw logs --follow 中读取 chat.id,检查 Bot API 的 getUpdates,或者(群组获允许后)运行 /whoami@<bot_username>。
运行时行为
- Telegram 在 Gateway 网关进程内运行。
- 路由是确定性的:Telegram 入站消息的回复会返回 Telegram(模型不会选择渠道)。
- 入站消息会规范化为共享渠道信封,其中包含回复元数据、媒体占位符,以及 Gateway 网关已观察到的回复所对应的持久化回复链上下文。
- 群组会话按群组 ID 隔离。论坛话题会追加
:topic:<threadId>。 - 私信消息可以携带
message_thread_id;OpenClaw 会为回复保留它。仅当 TelegramgetMe为该 Bot 报告has_topics_enabled: true时,私信话题会话才会拆分;否则私信会保留在扁平会话中。 - 长轮询使用 grammY runner,并按聊天/线程排序。Runner sink 的并发数使用
agents.defaults.maxConcurrent。 - 多账户启动会限制并发
getMe探测,避免大型 Bot 集群同时扇出所有账户探测。 - 每个 Gateway 网关进程都会保护长轮询,确保同一时间只有一个活动轮询器可以使用某个 Bot 令牌。持续出现的
getUpdates409 冲突表示另一个 OpenClaw Gateway 网关、脚本或外部轮询器正在使用同一令牌。 - 默认情况下,如果连续 120 秒没有完成
getUpdates活跃性检查,轮询看门狗会重启。仅当你的部署在长时间运行的工作期间出现误判的轮询停滞重启时,才应提高channels.telegram.pollingStallThresholdMs(30000-600000,支持按账户覆盖)。 - Telegram Bot API 不支持已读回执(
sendReadReceipts不适用)。
功能参考
实时流式预览(消息编辑)
OpenClaw 会在直接聊天、群组和话题中实时流式传输部分回复:先发送一条预览消息,然后反复调用 editMessageText,最后在原消息中完成回复。
channels.telegram.streaming可设为off | partial | block | progress(默认值:partial)- 较短的初始回答预览会经过防抖;如果运行仍处于活动状态,则会在有界延迟后实际发送
progress会为工具进度保留一条可编辑的状态草稿;如果回答活动先于工具进度出现,则显示稳定的状态标签;完成时清除该草稿,并将最终回答作为普通消息发送streaming.preview.toolProgress控制工具/进度更新是否复用同一条经过编辑的预览消息(启用预览流式传输时默认值为true)streaming.preview.commandText控制这些行中的命令/Exec 详细信息:raw(默认值)或status(仅显示工具标签)streaming.progress.commentary(默认值:false)选择在临时进度草稿中包含助手的评论/前言文本- 系统会检测旧版
channels.telegram.streamMode、布尔型streaming值和已停用的原生草稿预览键;运行openclaw doctor --fix以迁移它们
工具进度行是工具运行期间显示的简短状态更新(命令执行、文件读取、计划更新、补丁摘要,以及 app-server 模式下的 Codex 前言/评论)。Telegram 默认启用这些内容(与 v2026.4.22+ 的已发布行为一致)。
保留回答预览编辑,但隐藏工具进度行:
{ "channels": { "telegram": { "streaming": { "mode": "partial", "preview": { "toolProgress": false } } } }}保持工具进度可见,但隐藏命令/Exec 文本:
{ "channels": { "telegram": { "streaming": { "mode": "partial", "preview": { "commandText": "status" } } } }}progress 模式会显示工具进度,而不会通过编辑该消息来写入最终回答。将命令文本策略放在 streaming.progress 下:
{ "channels": { "telegram": { "streaming": { "mode": "progress", "progress": { "toolProgress": true, "commandText": "status" } } } }}streaming.mode: "off" 会禁用预览编辑,并抑制通用工具/进度消息,而不是将其作为独立状态消息发送;审批提示、媒体和错误仍通过正常的最终交付路径路由。streaming.preview.toolProgress: false 则仅保留回答预览编辑。
对于纯文本回复:短预览会在原消息中完成最终编辑;拆分为多条消息的长最终回答会复用预览作为第一个分块,然后仅发送剩余内容;进度模式的最终回答会清除状态草稿,并使用正常的最终交付;如果在确认完成前最终编辑失败,OpenClaw 会回退到正常的最终交付,并清理过期的预览。对于复杂回复(媒体载荷),OpenClaw 始终会回退到正常的最终交付,并清理预览。
预览流式传输和分块流式传输互斥——明确启用分块流式传输时,OpenClaw 会跳过预览流,以避免重复流式传输。
推理:/reasoning stream 会在生成期间将推理内容流式传输到实时预览中,然后在最终交付后删除推理预览(使用 /reasoning on 可保持其可见)。发送的最终回答不包含推理文本。
富消息格式
默认情况下,出站文本使用标准 Telegram HTML 消息,可在当前客户端中正常阅读:粗体、斜体、链接、代码、剧透、引用——而不是 Bot API 10.1 的富消息专用块(原生表格、详细信息、富媒体、公式)。
选择启用 Bot API 10.1 富消息:
{channels: {telegram: { richMessages: true,},},}启用后:系统会告知智能体此 Bot/账户可使用富消息;Markdown 文本会通过 OpenClaw 的 Markdown IR 渲染为 Telegram 富 HTML;显式富 HTML 载荷会保留 Bot API 10.1 支持的标签(标题、表格、详细信息、富媒体、公式);媒体说明文字仍使用 Telegram HTML 说明文字(富消息不会取代说明文字,并且说明文字上限为 1024 个字符)。
这样可避免模型文本接触 Telegram 的富 Markdown 标记,因此 $400-600K 等货币文本不会被解析为数学公式。较长的富文本会根据 Telegram 的限制自动拆分。超过 20 列限制的表格会回退为代码块。
默认值:关闭,以确保客户端兼容性——某些当前版本的 Desktop、Web、Android 和第三方客户端会将已接受的富消息显示为不受支持。除非使用该 Bot 的所有客户端都能渲染富消息,否则请保持关闭。/status 会显示当前会话的富消息是开启还是关闭。
链接预览默认开启。channels.telegram.linkPreview: false 会禁用富文本的自动实体检测。
原生命令和自定义命令
Telegram 的命令菜单会在启动时通过 setMyCommands 注册。commands.native: "auto" 会为 Telegram 启用原生命令。
添加自定义命令菜单项:
{channels: {telegram: { customCommands: [ { command: "backup", description: "Git 备份" }, { command: "generate", description: "创建图像" }, ],},},}规则:名称会被规范化(去除开头的 /,转换为小写);有效模式为 a-z、0-9、_,长度为 1-32;自定义命令不能覆盖原生命令;冲突项/重复项会被跳过并记录到日志中。
自定义命令仅是菜单项——不会自动实现相应行为。即使未显示在 Telegram 菜单中,输入插件/Skills 命令时,它们仍可工作。如果原生命令被禁用,内置命令会被移除;如果已配置,自定义命令/插件命令仍可注册。
常见设置失败:
- 如果裁剪并重试后,
setMyCommands failed仍伴随BOT_COMMANDS_TOO_MUCH,表示菜单依然溢出;请减少插件/Skills/自定义命令,或禁用channels.telegram.commands.native。 - 当直接使用 Bot API curl 命令可以正常工作,但
deleteWebhook、deleteMyCommands或setMyCommands失败并显示404: Not Found时,通常表示channels.telegram.apiRoot被设置为完整的/bot<TOKEN>端点。apiRoot必须仅为 Bot API 根地址;openclaw doctor --fix会移除意外添加的尾部/bot<TOKEN>。 getMe returned 401表示 Telegram 拒绝了已配置的 Bot 令牌。请使用当前 BotFather 令牌更新botToken、tokenFile或TELEGRAM_BOT_TOKEN(默认账户);OpenClaw 会在轮询前停止,因此不会将其报告为 webhook 清理失败。setMyCommands failed并伴随网络/fetch 错误,通常表示到api.telegram.org的出站 DNS/HTTPS 被阻止。
设备配对命令(device-pair 插件)
安装后:
/pair生成设置代码- 将代码粘贴到 iOS 应用中
/pair pending列出待处理的请求(包括角色/权限范围)- 批准:
/pair approve <requestId>、/pair approve(仅有一个待处理请求时)或/pair approve latest
如果设备使用已更改的身份验证详细信息(角色、权限范围、公钥)重试,先前的待处理请求会被带有新 requestId 的请求取代;批准前请重新运行 /pair pending。
更多详情:配对。
内联按钮
配置内联键盘范围:
{channels: {telegram: { capabilities: { inlineButtons: "allowlist", },},},}按账户覆盖:
{channels: {telegram: { accounts: { main: { capabilities: { inlineButtons: "allowlist", }, }, },},},}范围:off、dm、group、all、allowlist(默认值)。旧版 capabilities: ["inlineButtons"] 映射到 "all"。
消息操作示例:
{action: "send",channel: "telegram",to: "123456789",message: "选择一个选项:",buttons: [[ { text: "是", callback_data: "yes" }, { text: "否", callback_data: "no" },],[{ text: "取消", callback_data: "cancel" }],],}Mini App 按钮示例:
{action: "send",channel: "telegram",to: "123456789",message: "打开应用:",presentation: {blocks: [ { type: "buttons", buttons: [{ label: "启动", web_app: { url: "https://example.com/app" } }], },],},}web_app 按钮仅适用于用户与 Bot 之间的私聊。
未被已注册的插件交互处理程序认领的回调点击会作为文本传递给智能体:callback_data: <value>。
供智能体和自动化使用的 Telegram 消息操作
操作:
sendMessage(to、content,可选mediaUrl、replyToMessageId、messageThreadId)react(chatId、messageId、emoji)deleteMessage(chatId、messageId)editMessage(chatId、messageId、content或caption,可选包含内联按钮的presentation;仅编辑按钮时会更新回复标记)createForumTopic(chatId、name,可选iconColor、iconCustomEmojiId)
易用别名:send、react、delete、edit、sticker、sticker-search、topic-create。
功能开关:channels.telegram.actions.sendMessage、deleteMessage、reactions、sticker(默认:禁用)。edit、createForumTopic 和 editForumTopic 默认启用,没有专用开关。
运行时发送使用启动/重新加载时的活动配置/密钥快照,因此操作路径不会在每次发送时重新解析 SecretRef 值。
移除表情回应的语义:/tools/reactions。
回复线程标签
生成输出中的显式回复线程标签:
[[reply_to_current]]— 回复触发消息[[reply_to:<id>]]— 回复特定消息 ID
channels.telegram.replyToMode:off(默认)、first、all。
启用回复线程后,如果原始文本/说明文字可用,OpenClaw 会自动添加原生引用摘录。Telegram 将原生引用文本限制为 1024 个 UTF-16 代码单元;较长消息会从开头开始引用,如果 Telegram 拒绝该引用,则回退为普通回复。
off 仅禁用隐式回复线程;显式 [[reply_to_*]] 标签仍会生效。
论坛话题和线程行为
论坛超级群组:话题会话键追加 :topic:<threadId>;回复和正在输入状态以话题线程为目标;话题配置路径为 channels.telegram.groups.<chatId>.topics.<threadId>。
常规话题(threadId=1)属于特殊情况:发送消息时省略 message_thread_id(Telegram 会拒绝 sendMessage(...thread_id=1) 并返回 "thread not found"),但正在输入操作仍包含 message_thread_id(根据实测,这是显示正在输入指示器所必需的)。
除非被覆盖,否则话题条目会继承群组设置(requireMention、allowFrom、skills、systemPrompt、enabled、groupPolicy)。agentId 仅适用于话题,不会从群组默认设置中继承。topics."*" 为该群组中的每个话题设置默认值;精确的话题 ID 仍优先于 "*"。
按话题路由智能体:每个话题都可以通过话题配置中的 agentId 路由到不同的智能体,使其拥有自己的工作区、记忆和会话:
{ channels: { telegram: { groups: { "-1001234567890": { topics: { "1": { agentId: "main" }, // 常规话题 -> main 智能体 "3": { agentId: "zu" }, // 开发话题 -> zu 智能体 "5": { agentId: "coder" } // 代码审查 -> coder 智能体 } } } } }}这样,每个话题都有自己的会话键,例如 agent:zu:telegram:group:-1001234567890:topic:3。
持久 ACP 话题绑定:论坛话题可以通过顶层类型化绑定固定 ACP harness 会话(bindings[],其中包含 type: "acp"、match.channel: "telegram"、peer.kind: "group",以及类似 -1001234567890:topic:42 的含话题限定符 ID)。目前仅适用于群组/超级群组中的论坛话题。参见 ACP 智能体。
从聊天中生成线程绑定的 ACP:/acp spawn <agent> --thread here|auto 将当前话题绑定到新的 ACP 会话;后续消息会直接路由到该会话,OpenClaw 还会将生成确认消息固定在话题中。需要启用 channels.telegram.threadBindings.spawnSessions(默认:true)。
模板上下文会公开 MessageThreadId 和 IsForum。具有 message_thread_id 的私信聊天会保留回复元数据,但仅当 Telegram getMe 报告 has_topics_enabled: true 时才使用线程感知的会话键。
已停用的 dm.threadReplies 和 direct.*.threadReplies 覆盖项已被移除;BotFather 线程模式是唯一事实来源。运行 openclaw doctor --fix 以移除过时的配置键。
音频、视频和贴纸
音频消息
Telegram 区分语音消息和音频文件。默认:按音频文件处理;在智能体回复中添加标签 [[audio_as_voice]],可强制以语音消息形式发送。入站语音消息的转写文本在智能体上下文中会被标记为机器生成的不受信任文本,但提及检测仍使用原始转写文本,因此受提及限制的语音消息仍可正常工作。
{action: "send",channel: "telegram",to: "123456789",media: "https://example.com/voice.ogg",asVoice: true,}视频消息
Telegram 区分视频文件和视频消息。视频消息不支持说明文字;提供的消息文本会单独发送。
{action: "send",channel: "telegram",to: "123456789",media: "https://example.com/video.mp4",asVideoNote: true,}位置和地点
使用现有的 send 操作,并提供一个独立的 location 对象。坐标会发送原生位置图钉;同时添加 name 和 address 会发送原生地点卡片。发送位置时不能同时包含消息文本或媒体。
{action: "send",channel: "telegram",to: "123456789",location: {latitude: 48.858844,longitude: 2.294351,accuracy: 12,name: "埃菲尔铁塔",address: "巴黎战神广场",},}贴纸
入站:系统会下载并处理静态 WEBP(占位符 <media:sticker>);动画 TGS 和视频 WEBM 会被跳过。
贴纸上下文字段:Sticker.emoji、Sticker.setName、Sticker.fileId、Sticker.fileUniqueId、Sticker.cachedDescription。描述缓存在 OpenClaw SQLite 插件状态中,以减少重复的视觉调用。
启用贴纸操作:
{channels: {telegram: { actions: { sticker: true, },},},}发送:
{action: "sticker",channel: "telegram",to: "123456789",fileId: "CAACAgIAAxkBAAI...",}搜索缓存的贴纸:
{action: "sticker-search",channel: "telegram",query: "cat waving",limit: 5,}表情回应通知
Telegram 表情回应以 message_reaction 更新的形式到达,与消息负载分开。启用后,OpenClaw 会将类似 Telegram reaction added: 👍 by Alice (@alice) on msg 42 的系统事件加入队列。
channels.telegram.reactionNotifications:off | own | all(默认值:own)channels.telegram.reactionLevel:off | ack | minimal | extensive(默认值:minimal)
own 表示仅接收用户对机器人所发消息的表情回应(通过已发送消息缓存尽力实现)。表情回应事件仍遵循 Telegram 访问控制(dmPolicy、allowFrom、groupPolicy、groupAllowFrom);未经授权的发送者会被丢弃。
Telegram 不会在表情回应更新中提供话题 ID:非论坛群组路由到群聊会话;论坛群组路由到常规话题会话(:topic:1),而不是确切的原始话题。
轮询/webhook 的 allowed_updates 会自动包含 message_reaction。
确认表情回应
OpenClaw 处理入站消息时,ackReaction 会发送一个确认表情符号。messages.ackReactionScope 决定在何时发送。
表情符号解析顺序:
channels.telegram.accounts.<accountId>.ackReactionchannels.telegram.ackReactionmessages.ackReaction- 智能体身份表情符号回退(
agents.list[].identity.emoji,否则为 “👀”)
Telegram 要求使用 Unicode 表情符号(例如 “👀”);使用 "" 可为渠道或账号禁用该表情回应。
范围(messages.ackReactionScope,默认为 "group-mentions";目前不支持按 Telegram 账号或 Telegram 渠道覆盖):
all(私信 + 群组,包括环境房间事件)、direct(仅私信)、group-all(除环境房间事件外的所有群组消息,不包括私信)、group-mentions(在群组中 Bot 被提及时;不包括私信 — 默认值)、off / none(禁用)。
通过 Telegram 事件和命令写入配置
默认启用渠道配置写入(configWrites !== false)。由 Telegram 触发的写入包括群组迁移事件(migrate_to_chat_id,更新 channels.telegram.groups)以及 /config set / /config unset(需要启用命令)。
禁用:
{channels: {telegram: { configWrites: false,},},}长轮询与 webhook
默认使用长轮询。对于 webhook 模式,请设置 channels.telegram.webhookUrl 和 channels.telegram.webhookSecret;可选设置包括 webhookPath(默认为 /telegram-webhook)、webhookHost(默认为 127.0.0.1)、webhookPort(默认为 8787)、webhookCertPath(用于直接 IP 或无域名设置的自签名证书 PEM)。
在长轮询模式下,OpenClaw 仅在更新成功分派后才会持久化其重启水位;处理程序失败时,该更新在同一进程中仍可重试,而不会被标记为已完成。
本地监听器默认绑定到 127.0.0.1:8787。对于公共入口,请在本地端口前配置反向代理,或有意设置 webhookHost: "0.0.0.0"。
Webhook 模式会验证请求防护条件、Telegram 密钥令牌和 JSON 请求体,然后在返回空的 200 响应前,将更新提交到其持久化入口队列。成功的持久化接收会包含 x-openclaw-delivery-accepted: durable;健康检查、路由、身份验证、校验和存储错误响应不包含此标头。反向代理和主机控制器可以要求此标头,以区分 OpenClaw 接收与普通的空 200 响应,而无需根据响应时间推断是否已接收。
随后,OpenClaw 会通过长轮询所使用的相同按聊天/按话题 Bot 通道异步处理更新,因此耗时较长的智能体轮次不会阻塞 Telegram 的投递确认。
限制、重试和 CLI 目标
channels.telegram.textChunkLimit默认为 4000;streaming.chunkMode="newline"会优先按段落边界(空行)拆分,然后再按长度拆分。channels.telegram.mediaMaxMb(默认 100)限制入站和出站媒体的大小。channels.telegram.mediaGroupFlushMs(默认 500,范围 10-60000)控制相册/媒体组在 OpenClaw 将其作为一条入站消息分发之前的缓冲时长。如果相册中的部分内容到达较晚,请增大该值;如需降低相册回复延迟,请减小该值。channels.telegram.timeoutSeconds会覆盖 API 客户端超时时间(未设置时使用 grammY 默认值)。Bot 客户端会将低于 60 秒出站文本/输入状态请求保护时限的配置值提升到该时限,以免 grammY 在 OpenClaw 的传输保护和回退机制运行前中止可见回复的投递。长轮询仍使用 45 秒的getUpdates请求保护时限,避免空闲轮询被无限期搁置。channels.telegram.pollingStallThresholdMs默认为 120000;仅当轮询停滞重启出现误报时,才在 30000 到 600000 之间调整。- 群组上下文历史记录使用
channels.telegram.historyLimit或messages.groupChat.historyLimit(默认 50);0表示禁用。 - 当 Gateway 网关已观察到父消息时,回复/引用/转发的补充上下文会规范化到一个选定的对话上下文窗口中;已观察消息的缓存位于 OpenClaw SQLite 插件状态中,
openclaw doctor --fix会导入旧版旁路文件。Telegram 每次更新仅包含一层浅层reply_to_message,因此早于缓存的消息链仅限于该载荷中包含的内容。 - Telegram 允许列表主要用于限制谁能触发智能体,并非完整的补充上下文脱敏边界。
- 私信历史记录:
channels.telegram.dmHistoryLimit、channels.telegram.dms["<user_id>"].historyLimit。 channels.telegram.retry适用于 Telegram 发送辅助函数(CLI/工具/操作)遇到的可恢复出站 API 错误。入站最终回复的投递会针对连接前失败执行有界的安全发送重试,但不会重试可能导致可见消息重复的、发送后结果不明确的网络信封。
CLI 和消息工具的发送目标可接受数字聊天 ID、用户名或论坛主题目标:
openclaw message send --channel telegram --target 123456789 --message "你好"openclaw message send --channel telegram --target @name --message "你好"openclaw message send --channel telegram --target -1001234567890:topic:42 --message "主题你好"投票使用 openclaw message poll,并支持论坛主题:
openclaw message poll --channel telegram --target 123456789 \--poll-question "发布吗?" --poll-option "是" --poll-option "否"openclaw message poll --channel telegram --target -1001234567890:topic:42 \--poll-question "选择时间" --poll-option "上午 10 点" --poll-option "下午 2 点" \--poll-duration-seconds 300 --poll-public仅限 Telegram 的投票标志:--poll-duration-seconds(5-600)、--poll-anonymous、--poll-public、--thread-id(或 :topic: 目标)。--poll-option 可重复 2-12 次(Telegram 的选项数量上限)。
Telegram 发送还支持:使用带有 buttons 块的 --presentation 创建内联键盘(前提是 channels.telegram.capabilities.inlineButtons 允许);使用 --pin 或 --delivery '{"pin":true}' 请求置顶投递(前提是 Bot 可以在该聊天中置顶消息);使用 --force-document 将出站图片、GIF 和视频作为文档发送,而不是通过压缩图片、动画或视频上传方式发送。
操作限制:channels.telegram.actions.sendMessage=false 会禁用包括投票在内的所有出站消息;channels.telegram.actions.poll=false 会禁用投票创建,但仍允许常规发送。
Telegram 中的 Exec 审批
Telegram 支持在审批者私信中进行 Exec 审批,也可以选择在发起操作的聊天或主题中发布提示。审批者必须使用数字 Telegram 用户 ID。
channels.telegram.execApprovals.enabled(当至少可以解析一位审批者时,"auto"会启用)channels.telegram.execApprovals.approvers(回退到commands.ownerAllowFrom中的数字所有者 ID)channels.telegram.execApprovals.target:dm(默认)|channel|bothagentFilter、sessionFilter
channels.telegram.allowFrom、groupAllowFrom 和 defaultTo 控制谁可以与 Bot 对话,以及 Bot 将常规回复发送到哪里——它们不会让某人成为 Exec 审批者。如果尚不存在命令所有者,首次获批的私信配对会初始化 commands.ownerAllowFrom,因此单所有者设置无需在 execApprovals.approvers 下重复填写 ID。
渠道投递会在聊天中显示命令文本;仅在可信群组/主题中启用 channel 或 both。当提示发送到论坛主题时,OpenClaw 会为审批提示和后续消息保留该主题。默认情况下,Exec 审批会在 30 分钟后过期。
内联审批按钮还要求 channels.telegram.capabilities.inlineButtons 允许目标界面(dm、group 或 all)。以 plugin: 为前缀的审批 ID 通过插件审批解析;其他 ID 会优先通过 Exec 审批解析。
请参阅 Exec 审批。
错误回复控制
当智能体遇到投递错误或提供商错误时,错误策略控制是否将错误消息发送到 Telegram 聊天:
| 键 | 值 | 默认值 | 说明 |
|---|---|---|---|
channels.telegram.errorPolicy |
always、once、silent |
always |
always 将每条错误消息发送到聊天。once 在每个冷却窗口内对每条唯一错误消息仅发送一次(抑制重复的相同错误)。silent 从不向聊天发送错误消息。 |
channels.telegram.errorCooldownMs |
数字(毫秒) | 14400000(4h) |
once 策略的冷却窗口。发送错误后,在此间隔结束前会抑制相同消息。防止故障期间出现大量错误消息。 |
支持按账号、群组和主题进行覆盖(继承规则与其他 Telegram 配置键相同)。
{ channels: { telegram: { errorPolicy: "always", errorCooldownMs: 120000, groups: { "-1001234567890": { errorPolicy: "silent", // 抑制此群组中的错误 }, }, }, },}故障排查
Bot 不响应群组中未提及它的消息
- 如果
requireMention=false,Telegram 隐私模式必须允许完整可见性:在 BotFather 中执行/setprivacy-> Disable,然后从群组中移除 Bot 并重新添加。 - 当配置预期接收群组中未提及 Bot 的消息时,
openclaw channels status会发出警告。 openclaw channels status --probe会检查明确的数字群组 ID;无法探测通配符"*"的成员资格。- 快速会话测试:
/activation always。
Bot 完全看不到群组消息
- 当存在
channels.telegram.groups时,必须列出该群组(或包含"*")。 - 验证 Bot 是否为群组成员。
- 查看
openclaw logs --follow中的跳过原因。
命令仅部分可用或完全不可用
- 授权你的发送者身份(通过配对和/或数字
allowFrom);即使群组策略为open,命令授权仍然适用。 setMyCommands failed并出现BOT_COMMANDS_TOO_MUCH表示原生菜单条目过多;请减少插件/Skills/自定义命令,或禁用原生菜单。- 启动时的
deleteMyCommands/setMyCommands调用和sendChatAction输入状态调用均有时限限制,并会在请求超时时通过 Telegram 的传输回退机制重试一次。持续的网络/fetch 错误通常表示无法通过 DNS/HTTPS 访问api.telegram.org。
启动报告未授权令牌
getMe returned 401表示所配置 Bot 令牌发生 Telegram 身份验证失败。请在 BotFather 中重新复制或生成令牌,然后更新channels.telegram.botToken、tokenFile、accounts.<id>.botToken或TELEGRAM_BOT_TOKEN(默认账号)。- 启动期间出现
deleteWebhook 401 Unauthorized同样表示身份验证失败;将其视为“没有 Webhook”只会把同一个无效令牌错误推迟到后续 API 调用。
轮询或网络不稳定
- Node 22+ 配合自定义 fetch/代理使用时,如果
AbortSignal类型不匹配,可能触发立即中止行为。 - 某些主机会优先将
api.telegram.org解析为 IPv6;损坏的 IPv6 出站连接会导致间歇性 API 失败。 - 日志中的
TypeError: fetch failed或Network request for 'getUpdates' failed!会作为可恢复网络错误进行重试。 - 在轮询启动期间,OpenClaw 会为 grammY 复用启动时成功的
getMe探测结果,因此运行器在首次getUpdates之前无需再次执行getMe。 - 如果在轮询启动期间
deleteWebhook因暂时性网络错误失败,OpenClaw 会继续进入长轮询,而不会再次执行轮询前控制平面调用。仍处于活动状态的 Webhook 随后会表现为getUpdates冲突;OpenClaw 会重建传输并重试 Webhook 清理。 - 如果 Telegram 套接字按较短的固定周期重新建立,请检查
channels.telegram.timeoutSeconds是否过低——Bot 客户端会将低于出站和getUpdates请求保护时限的配置值提升到相应时限,但旧版可能会在该值低于这些保护时限时中止每次轮询或回复。 - 日志中的
Polling stall detected表示默认情况下,OpenClaw 在 120 秒内未检测到已完成的长轮询存活活动后,会重启轮询并重建传输。 - 当正在运行的轮询账号在启动宽限期后仍未完成
getUpdates、正在运行的 Webhook 账号在启动宽限期后仍未完成setWebhook,或最近一次成功的轮询传输活动已过期时,openclaw channels status --probe和openclaw doctor会发出警告。 - 仅当长时间运行的
getUpdates调用状态正常,但你的主机仍误报轮询停滞重启时,才增大channels.telegram.pollingStallThresholdMs。持续停滞通常表示访问api.telegram.org时存在代理、DNS、IPv6 或 TLS 出站连接问题。 - Telegram 的 Bot API 传输会遵循进程代理环境变量:
HTTP_PROXY、HTTPS_PROXY、ALL_PROXY及其小写变体。NO_PROXY/no_proxy仍可绕过api.telegram.org。 - 如果服务环境中设置了
OPENCLAW_PROXY_URL,且不存在标准代理环境变量,Telegram 也会使用该 URL 进行 Bot API 传输。 - 在直接出站连接/TLS 不稳定的 VPS 主机上,通过代理路由 Telegram API 调用:
channels:telegram:proxy: socks5://<user>:<password>@proxy-host:1080- Node 22+ 默认为
autoSelectFamily=true(WSL2 除外)。Telegram DNS 结果顺序依次遵循OPENCLAW_TELEGRAM_DNS_RESULT_ORDER、channels.telegram.network.dnsResultOrder和进程默认值(例如NODE_OPTIONS=--dns-result-order=ipv4first);如果均不适用,则在 Node 22+ 上回退到ipv4first。 - 在 WSL2 上,或仅使用 IPv4 效果更好时,强制指定地址族选择:
channels:telegram:network: autoSelectFamily: false- 默认情况下,Telegram 媒体下载已允许 RFC 2544 基准测试地址范围的解析结果(
198.18.0.0/15)。如果受信任的 fake-IP 或透明代理在媒体下载期间将api.telegram.org重写为其他私有/内部/特殊用途地址,请选择启用仅限 Telegram 的绕过:
channels:telegram:network: dangerouslyAllowPrivateNetwork: true- 也可以通过
channels.telegram.accounts.<accountId>.network.dangerouslyAllowPrivateNetwork为每个账号单独启用相同的选项。 - 如果你的代理将 Telegram 媒体主机解析到
198.18.x.x,请先保持危险标志关闭——默认情况下已允许此地址范围。
- 临时环境变量覆盖:
OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1、OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1、OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first。 - 验证 DNS 解析结果:
dig +short api.telegram.org Adig +short api.telegram.org AAAA更多帮助:渠道故障排除。
配置参考
主要参考:配置参考 - Telegram。
高信号 Telegram 字段
- 启动/身份验证:
enabled、botToken、tokenFile(必须是常规文件;拒绝符号链接)、accounts.* - 访问控制:
dmPolicy、allowFrom、groupPolicy、groupAllowFrom、groups、groups.*.topics.*、顶层bindings[](type: "acp") - 话题默认值:
groups.<chatId>.topics."*"应用于未匹配的论坛话题;精确的话题 ID 会覆盖该值 - Exec 审批:
execApprovals、accounts.*.execApprovals - 命令/菜单:
commands.native、commands.nativeSkills、customCommands - 线程/回复:
replyToMode、threadBindings - 流式传输:
streaming(模式为off | partial | block | progress)、streaming.preview.toolProgress - 格式/递送:
textChunkLimit、streaming.chunkMode、richMessages、markdown.tables(off | bullets | code | block)、linkPreview、responsePrefix - 媒体/网络:
mediaMaxMb、mediaGroupFlushMs、timeoutSeconds、pollingStallThresholdMs、retry、network.autoSelectFamily、network.dangerouslyAllowPrivateNetwork、proxy - 自定义 API 根地址:
apiRoot(仅限 Bot API 根地址;不要包含/bot<TOKEN>)、trustedLocalFileRoots(自托管 Bot API 的绝对file_path根目录) - webhook:
webhookUrl、webhookSecret、webhookPath、webhookHost、webhookPort、webhookCertPath - 操作/能力:
capabilities.inlineButtons、actions.sendMessage|editMessage|deleteMessage|reactions|sticker|createForumTopic|editForumTopic - 表情回应:
reactionNotifications、reactionLevel - 错误:
errorPolicy、errorCooldownMs、silentErrorReplies - 写入/历史记录:
configWrites、historyLimit、dmHistoryLimit、dms.*.historyLimit