消息平台

Telegram

通过 grammY 支持可用于生产环境的机器人私信和群组。默认模式是长轮询;webhook 模式是可选的。

快速设置

  • Create the bot token in BotFather

    打开 Telegram 并与 @BotFather 聊天(确认用户名正好是 @BotFather)。

    运行 /newbot,按提示操作,并保存令牌。

  • Configure token and DM policy

    json5
    {channels: {telegram: {  enabled: true,  botToken: "123:abc",  dmPolicy: "pairing",  groups: { "*": { requireMention: true } },},},}

    环境变量回退:TELEGRAM_BOT_TOKEN=...(仅默认账户)。 Telegram 使用 openclaw channels login telegram;在配置/环境变量中配置令牌,然后启动 Gateway 网关。

  • Start gateway and approve first DM

    bash
    openclaw gatewayopenclaw pairing list telegramopenclaw pairing approve telegram <CODE>

    配对码会在 1 小时后过期。

  • Add the bot to a group

    将机器人添加到你的群组,然后获取群组访问需要的两个 ID:

    • 你的 Telegram 用户 ID,用于 allowFrom / groupAllowFrom
    • Telegram 群组聊天 ID,用作 channels.telegram.groups 下的键

    首次设置时,从 openclaw logs --follow、转发 ID 机器人或 Bot API getUpdates 获取群组聊天 ID。允许该群组后,/whoami@<bot_username> 可以确认用户和群组 ID。

    -100 开头的负数 Telegram 超级群组 ID 是群组聊天 ID。把它们放在 channels.telegram.groups 下,而不是 groupAllowFrom 下。

  • Telegram 端设置

    Privacy mode and group visibility

    Telegram 机器人默认启用 Privacy Mode,这会限制它们接收的群组消息。

    如果机器人必须看到所有群组消息,可以:

    • 通过 /setprivacy 禁用隐私模式,或
    • 将机器人设为群组管理员。

    切换隐私模式时,在每个群组中移除并重新添加机器人,以便 Telegram 应用更改。

    Group permissions

    管理员状态在 Telegram 群组设置中控制。

    管理员机器人会接收所有群组消息,这对常驻群组行为很有用。

    Helpful BotFather toggles
    • /setjoingroups 用于允许/拒绝添加到群组
    • /setprivacy 用于群组可见性行为

    访问控制和激活

    DM policy

    channels.telegram.dmPolicy 控制私信访问:

    • pairing(默认)
    • allowlist(要求 allowFrom 中至少有一个发送者 ID)
    • open(要求 allowFrom 包含 "*"
    • disabled

    dmPolicy: "open" 搭配 allowFrom: ["*"] 会让任何找到或猜到机器人用户名的 Telegram 账户都能命令该机器人。只应将它用于有严格工具限制的有意公开机器人;单所有者机器人应使用 allowlist 并配置数字用户 ID。

    channels.telegram.allowFrom 接受数字 Telegram 用户 ID。接受并规范化 telegram: / tg: 前缀。 在多账户配置中,限制性的顶层 channels.telegram.allowFrom 会被视为安全边界:账户级 allowFrom: ["*"] 条目不会让该账户公开,除非合并后的有效账户允许列表仍包含显式通配符。 dmPolicy: "allowlist" 搭配空 allowFrom 会阻止所有私信,并被配置验证拒绝。 设置只会询问数字用户 ID。 如果你已升级且配置包含 @username 允许列表条目,请运行 openclaw doctor --fix 来解析它们(尽力而为;需要 Telegram 机器人令牌)。 如果你之前依赖配对存储允许列表文件,openclaw doctor --fix 可以在允许列表流程中将条目恢复到 channels.telegram.allowFrom(例如当 dmPolicy: "allowlist" 还没有显式 ID 时)。

    对于单所有者机器人,优先使用 dmPolicy: "allowlist" 并配置显式数字 allowFrom ID,以便在配置中保持访问策略持久(而不是依赖之前的配对批准)。

    常见混淆:私信配对批准并不意味着“这个发送者在所有地方都已授权”。 配对授予私信访问权限。如果还没有命令所有者,第一次批准的配对还会设置 commands.ownerAllowFrom,从而为仅所有者命令和 exec 审批提供显式操作员账户。 群组发送者授权仍来自显式配置允许列表。 如果你想要“我授权一次,私信和群组命令都能用”,请将你的数字 Telegram 用户 ID 放入 channels.telegram.allowFrom;对于仅所有者命令,请确保 commands.ownerAllowFrom 包含 telegram:<your user id>

    查找你的 Telegram 用户 ID

    更安全(无第三方机器人):

    1. 私信你的机器人。
    2. 运行 openclaw logs --follow
    3. 读取 from.id

    官方 Bot API 方法:

    bash
    curl "https://api.telegram.org/bot<bot_token>/getUpdates"

    第三方方法(隐私性较低):@userinfobot@getidsbot

    Group policy and allowlists

    两个控制项会一起生效:

    1. 允许哪些群组channels.telegram.groups

      • 没有 groups 配置:
        • 搭配 groupPolicy: "open":任何群组都可以通过群组 ID 检查
        • 搭配 groupPolicy: "allowlist"(默认):群组会被阻止,直到你添加 groups 条目(或 "*"
      • 已配置 groups:作为允许列表生效(显式 ID 或 "*"
    2. 群组中允许哪些发送者channels.telegram.groupPolicy

      • open
      • allowlist(默认)
      • disabled

    groupAllowFrom 用于群组发送者过滤。如果未设置,Telegram 会回退到 allowFromgroupAllowFrom 条目应是数字 Telegram 用户 ID(telegram: / tg: 前缀会被规范化)。 不要把 Telegram 群组或超级群组聊天 ID 放入 groupAllowFrom。负数聊天 ID 属于 channels.telegram.groups。 非数字条目会被发送者授权忽略。 安全边界(2026.2.25+):群组发送者身份验证不会继承私信配对存储批准。 配对仅适用于私信。对于群组,请设置 groupAllowFrom 或按群组/主题设置 allowFrom。 如果未设置 groupAllowFrom,Telegram 会回退到配置 allowFrom,而不是配对存储。 单所有者机器人的实用模式:在 channels.telegram.allowFrom 中设置你的用户 ID,保持 groupAllowFrom 未设置,并在 channels.telegram.groups 下允许目标群组。 运行时注意事项:如果完全缺少 channels.telegram,运行时默认采用故障关闭的 groupPolicy="allowlist",除非显式设置了 channels.defaults.groupPolicy

    仅所有者群组设置:

    json5
    {channels: {telegram: {  enabled: true,  dmPolicy: "pairing",  allowFrom: ["&lt;YOUR_TELEGRAM_USER_ID&gt;"],  groupPolicy: "allowlist",  groups: {    "&lt;GROUP_CHAT_ID&gt;": {      requireMention: true,    },  },},},}

    在群组中用 @<bot_username> ping 测试。requireMention: true 时,普通群组消息不会触发机器人。

    示例:允许某个特定群组中的任何成员:

    json5
    {channels: {telegram: {  groups: {    "-1001234567890": {      groupPolicy: "open",      requireMention: false,    },  },},},}

    示例:只允许某个特定群组中的特定用户:

    json5
    {channels: {telegram: {  groups: {    "-1001234567890": {      requireMention: true,      allowFrom: ["8734062810", "745123456"],    },  },},},}

    Mention behavior

    群组回复默认需要提及。

    提及可以来自:

    • 原生 @botusername 提及,或
    • 以下位置中的提及模式:
      • agents.list[].groupChat.mentionPatterns
      • messages.groupChat.mentionPatterns

    会话级命令开关:

    • /activation always
    • /activation mention

    这些只更新会话状态。使用配置实现持久化。

    持久化配置示例:

    json5
    {channels: {telegram: {  groups: {    "*": { requireMention: false },  },},},}

    获取群组聊天 ID:

    • 将群组消息转发给 @userinfobot / @getidsbot
    • 或从 openclaw logs --follow 读取 chat.id
    • 或检查 Bot API getUpdates
    • 允许该群组后,如果原生命令已启用,请运行 /whoami@<bot_username>

    运行时行为

    • Telegram 由 Gateway 网关进程拥有。
    • 路由是确定性的:Telegram 入站消息会回复到 Telegram(模型不会选择渠道)。
    • 入站消息会规范化到共享渠道信封中,包含回复元数据、媒体占位符,以及 Gateway 网关已观察到的 Telegram 回复的持久化回复链上下文。
    • 群组会话按群组 ID 隔离。论坛主题会追加 :topic:<threadId> 以保持主题隔离。
    • 私信消息可以携带 message_thread_id;OpenClaw 会为回复保留线程 ID,但默认将私信保留在扁平会话上。当你有意想要私信主题会话隔离时,请配置 channels.telegram.dm.threadReplies: "inbound"channels.telegram.direct.<chatId>.threadReplies: "inbound"requireTopic: true,或匹配的主题配置。
    • 长轮询使用 grammY runner,并按每个聊天/每个线程排序。整体 runner sink 并发使用 agents.defaults.maxConcurrent
    • 长轮询在每个 Gateway 网关进程内受保护,因此同一时间只有一个活跃轮询器可以使用一个机器人令牌。如果你仍看到 getUpdates 409 冲突,可能是另一个 OpenClaw Gateway 网关、脚本或外部轮询器正在使用同一个令牌。
    • 默认情况下,长轮询 watchdog 重启会在 120 秒内没有完成的 getUpdates 活性后触发。只有当你的部署在长时间运行工作期间仍出现误判的轮询停滞重启时,才增加 channels.telegram.pollingStallThresholdMs。该值以毫秒为单位,允许范围为 30000600000;支持按账户覆盖。
    • Telegram Bot API 不支持已读回执(sendReadReceipts 不适用)。

    功能参考

    Live stream preview (message edits)

    OpenClaw 可以实时流式传输部分回复:

    • 直接聊天:预览消息 + editMessageText
    • 群组/主题:预览消息 + editMessageText

    要求:

    • channels.telegram.streamingoff | partial | block | progress(默认:partial
    • progress 会为工具进度保留一条可编辑的状态草稿,在完成时清除它,并将最终回答作为普通消息发送
    • streaming.preview.toolProgress 控制工具/进度更新是否复用同一条已编辑的预览消息(默认:预览流式传输启用时为 true
    • streaming.preview.commandText 控制这些工具进度行内的命令/Exec 详情:raw(默认,保留已发布行为)或 status(仅工具标签)
    • 会检测旧版 channels.telegram.streamMode 和布尔值 streaming;运行 openclaw doctor --fix 将它们迁移到 channels.telegram.streaming.mode

    工具进度预览更新是在工具运行时显示的简短状态行,例如命令执行、文件读取、计划更新或补丁摘要。Telegram 默认保持启用这些更新,以匹配 v2026.4.22 及更高版本中已发布的 OpenClaw 行为。若要保留回答文本的已编辑预览,但隐藏工具进度行,请设置:

    json
    {  "channels": {    "telegram": {      "streaming": {        "mode": "partial",        "preview": {          "toolProgress": false        }      }    }  }}

    若要保持工具进度可见,但隐藏命令/Exec 文本,请设置:

    json
    {  "channels": {    "telegram": {      "streaming": {        "mode": "partial",        "preview": {          "commandText": "status"        }      }    }  }}

    当你希望显示可见的工具进度,但不将最终回答编辑到同一条消息中时,请使用 progress 模式。将命令文本策略放在 streaming.progress 下:

    json
    {  "channels": {    "telegram": {      "streaming": {        "mode": "progress",        "progress": {          "toolProgress": true,          "commandText": "status"        }      }    }  }}

    仅当你希望只交付最终内容时才使用 streaming.mode: "off":Telegram 预览编辑会被禁用,通用工具/进度闲聊会被抑制,而不是作为独立状态消息发送。审批提示、媒体载荷和错误仍会通过普通最终交付路径路由。当你只想保留回答预览编辑,同时隐藏工具进度状态行时,请使用 streaming.preview.toolProgress: false

    对于纯文本回复:

    • 简短私信/群组/主题预览:OpenClaw 会保留同一条预览消息,并就地执行最终编辑
    • 会拆分为多条 Telegram 消息的长文本最终内容,会在可能时复用现有预览作为第一个最终分块,然后只发送剩余分块
    • 进度模式的最终内容会清除状态草稿,并使用普通最终交付,而不是将草稿编辑成回答
    • 如果在完成文本被确认之前最终编辑失败,OpenClaw 会使用普通最终交付,并清理过期预览

    对于复杂回复(例如媒体载荷),OpenClaw 会回退到普通最终交付,然后清理预览消息。

    预览流式传输独立于分块流式传输。当 Telegram 明确启用分块流式传输时,OpenClaw 会跳过预览流,以避免双重流式传输。

    仅限 Telegram 的推理流:

    • /reasoning stream 会在生成期间将推理发送到实时预览
    • 推理预览会在最终交付后删除;当推理应保持可见时,请使用 /reasoning on
    • 最终回答发送时不包含推理文本
    格式化和 HTML 回退

    出站文本使用 Telegram parse_mode: "HTML"

    • 类 Markdown 文本会渲染为 Telegram 安全的 HTML。
    • 支持的 Telegram HTML 标签会保留;不支持的 HTML 会被转义。
    • 如果 Telegram 拒绝解析后的 HTML,OpenClaw 会以纯文本重试。

    链接预览默认启用,可通过 channels.telegram.linkPreview: false 禁用。

    原生命令和自定义命令

    Telegram 命令菜单注册会在启动时通过 setMyCommands 处理。

    原生命令默认值:

    • commands.native: "auto" 为 Telegram 启用原生命令

    添加自定义命令菜单条目:

    json5
    {channels: {telegram: {  customCommands: [    { command: "backup", description: "Git backup" },    { command: "generate", description: "Create an image" },  ],},},}

    规则:

    • 名称会被规范化(去除前导 /,转为小写)
    • 有效模式:a-z0-9_,长度 1..32
    • 自定义命令不能覆盖原生命令
    • 冲突/重复项会被跳过并记录日志

    注意:

    • 自定义命令只是菜单条目;它们不会自动实现行为
    • 即使未显示在 Telegram 菜单中,插件/技能命令在输入时仍然可以工作

    如果原生命令被禁用,内置命令会被移除。自定义/插件命令如果已配置,仍可能注册。

    常见设置失败:

    • setMyCommands failed 且带有 BOT_COMMANDS_TOO_MUCH 表示 Telegram 菜单在裁剪后仍然溢出;减少插件/技能/自定义命令,或禁用 channels.telegram.commands.native
    • 当直接 Bot API curl 命令可用,但 deleteWebhookdeleteMyCommandssetMyCommands 失败并显示 404: Not Found 时,可能表示 channels.telegram.apiRoot 被设置成了完整的 /bot&lt;TOKEN&gt; 端点。apiRoot 必须只是 Bot API 根路径,且 openclaw doctor --fix 会移除意外的尾随 /bot&lt;TOKEN&gt;
    • getMe returned 401 表示 Telegram 拒绝了已配置的机器人令牌。使用当前 BotFather 令牌更新 botTokentokenFileTELEGRAM_BOT_TOKEN;OpenClaw 会在轮询前停止,因此这不会被报告为 webhook 清理失败。
    • setMyCommands failed 且带有网络/fetch 错误通常表示到 api.telegram.org 的出站 DNS/HTTPS 被阻止。

    设备配对命令(device-pair 插件)

    安装 device-pair 插件后:

    1. /pair 生成设置代码
    2. 将代码粘贴到 iOS 应用
    3. /pair pending 列出待处理请求(包括角色/范围)
    4. 批准请求:
      • /pair approve <requestId> 用于显式批准
      • 当只有一个待处理请求时使用 /pair approve
      • /pair approve latest 用于最近的请求

    设置代码携带一个短期有效的引导令牌。内置引导交接会将主节点令牌保持在 scopes: [];任何被交接的操作员令牌都会限制在 operator.approvalsoperator.readoperator.talk.secretsoperator.write 内。引导范围检查带有角色前缀,因此该操作员允许列表只满足操作员请求;非操作员角色仍需要位于其自身角色前缀下的范围。

    如果设备用变更后的身份验证详情重试(例如角色/范围/公钥),之前的待处理请求会被取代,新请求会使用不同的 requestId。批准前请重新运行 /pair pending

    更多详情:配对

    内联按钮

    配置内联键盘范围:

    json5
    {channels: {telegram: {  capabilities: {    inlineButtons: "allowlist",  },},},}

    按账户覆盖:

    json5
    {channels: {telegram: {  accounts: {    main: {      capabilities: {        inlineButtons: "allowlist",      },    },  },},},}

    范围:

    • off
    • dm
    • group
    • all
    • allowlist(默认)

    旧版 capabilities: ["inlineButtons"] 会映射到 inlineButtons: "all"

    消息操作示例:

    json5
    {action: "send",channel: "telegram",to: "123456789",message: "Choose an option:",buttons: [[  { text: "Yes", callback_data: "yes" },  { text: "No", callback_data: "no" },],[{ text: "Cancel", callback_data: "cancel" }],],}

    回调点击会作为文本传递给智能体: callback_data: <value>

    面向智能体和自动化的 Telegram 消息操作

    Telegram 工具操作包括:

    • sendMessagetocontent、可选 mediaUrlreplyToMessageIdmessageThreadId
    • reactchatIdmessageIdemoji
    • deleteMessagechatIdmessageId
    • editMessagechatIdmessageIdcontent
    • createForumTopicchatIdname、可选 iconColoriconCustomEmojiId

    频道消息操作提供符合人体工学的别名(sendreactdeleteeditstickersticker-searchtopic-create)。

    门控控制:

    • channels.telegram.actions.sendMessage
    • channels.telegram.actions.deleteMessage
    • channels.telegram.actions.reactions
    • channels.telegram.actions.sticker(默认:禁用)

    注意:edittopic-create 当前默认启用,且没有单独的 channels.telegram.actions.* 开关。 运行时发送使用活动的配置/密钥快照(启动/重新加载),因此操作路径不会在每次发送时执行临时 SecretRef 重新解析。

    移除回应的语义:/tools/reactions

    回复线程标签

    Telegram 支持在生成的输出中使用显式回复线程标签:

    • [[reply_to_current]] 回复触发消息
    • [[reply_to:<id>]] 回复特定 Telegram 消息 ID

    channels.telegram.replyToMode 控制处理方式:

    • off(默认)
    • first
    • all

    当回复线程启用且原始 Telegram 文本或说明文字可用时,OpenClaw 会自动包含原生 Telegram 引用摘录。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)
    • 输入状态操作仍包含 message_thread_id

    主题继承:主题条目会继承群组设置,除非被覆盖(requireMentionallowFromskillssystemPromptenabledgroupPolicy)。 agentId 仅限主题,不会从群组默认值继承。

    按主题智能体路由:每个主题都可以通过在主题配置中设置 agentId 路由到不同智能体。这会为每个主题提供自己的隔离工作区、记忆和会话。示例:

    json5
    {  channels: {    telegram: {      groups: {        "-1001234567890": {          topics: {            "1": { agentId: "main" },      // General topic → main agent            "3": { agentId: "zu" },        // Dev topic → zu agent            "5": { agentId: "coder" }      // Code review → coder agent          }        }      }    }  }}

    然后每个话题都有自己的会话键:agent:zu:telegram:group:-1001234567890:topic:3

    持久 ACP 话题绑定:论坛话题可以通过顶层类型化 ACP 绑定(bindings[],其中包含 type: "acp"match.channel: "telegram"peer.kind: "group",以及像 -1001234567890:topic:42 这样带话题限定的 ID)固定 ACP harness 会话。目前范围限定为群组/超级群组中的论坛话题。请参阅 ACP Agents

    从聊天中生成线程绑定的 ACP/acp spawn <agent> --thread here|auto 会将当前话题绑定到新的 ACP 会话;后续消息会直接路由到那里。OpenClaw 会在话题内固定生成确认消息。需要保持启用 channels.telegram.threadBindings.spawnSessions(默认:true)。

    模板上下文公开 MessageThreadIdIsForum。带有 message_thread_id 的私信聊天默认保留私信路由,并在扁平会话上保留回复元数据;只有在配置了 threadReplies: "inbound"threadReplies: "always"requireTopic: true 或匹配的话题配置时,它们才会使用线程感知的会话键。使用顶层 channels.telegram.dm.threadReplies 设置账号默认值,或使用 direct.<chatId>.threadReplies 设置单个私信。

    音频、视频和贴纸

    音频消息

    Telegram 会区分语音便笺和音频文件。

    • 默认:音频文件行为
    • 在智能体回复中添加标签 [[audio_as_voice]] 可强制以语音便笺发送
    • 入站语音便笺转录会在智能体上下文中被标记为机器生成的、不可信文本;提及检测仍使用原始转录,因此受提及门控的语音消息会继续工作。

    消息动作示例:

    json5
    {action: "send",channel: "telegram",to: "123456789",media: "https://example.com/voice.ogg",asVoice: true,}

    视频消息

    Telegram 会区分视频文件和视频便笺。

    消息动作示例:

    json5
    {action: "send",channel: "telegram",to: "123456789",media: "https://example.com/video.mp4",asVideoNote: true,}

    视频便笺不支持字幕;提供的消息文本会单独发送。

    贴纸

    入站贴纸处理:

    • 静态 WEBP:下载并处理(占位符 <media:sticker>
    • 动画 TGS:跳过
    • 视频 WEBM:跳过

    贴纸上下文字段:

    • Sticker.emoji
    • Sticker.setName
    • Sticker.fileId
    • Sticker.fileUniqueId
    • Sticker.cachedDescription

    贴纸缓存文件:

    • ~/.openclaw/telegram/sticker-cache.json

    贴纸会被描述一次(如果可能)并缓存,以减少重复的视觉调用。

    启用贴纸动作:

    json5
    {channels: {telegram: {  actions: {    sticker: true,  },},},}

    发送贴纸动作:

    json5
    {action: "sticker",channel: "telegram",to: "123456789",fileId: "CAACAgIAAxkBAAI...",}

    搜索已缓存的贴纸:

    json5
    {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.reactionNotificationsoff | own | all(默认:own
    • channels.telegram.reactionLeveloff | ack | minimal | extensive(默认:minimal

    说明:

    • own 表示仅用户对机器人发送的消息做出的回应(通过已发送消息缓存尽力实现)。
    • 回应事件仍遵守 Telegram 访问控制(dmPolicyallowFromgroupPolicygroupAllowFrom);未经授权的发送者会被丢弃。
    • Telegram 不会在回应更新中提供线程 ID。
      • 非论坛群组路由到群组聊天会话
      • 论坛群组路由到群组通用话题会话(:topic:1),而不是确切的原始话题

    轮询/webhook 的 allowed_updates 会自动包含 message_reaction

    确认回应

    ackReaction 会在 OpenClaw 处理入站消息时发送一个确认表情符号。

    解析顺序:

    • channels.telegram.accounts.<accountId>.ackReaction
    • channels.telegram.ackReaction
    • messages.ackReaction
    • 智能体身份表情符号回退(agents.list[].identity.emoji,否则为 "👀")

    说明:

    • Telegram 需要 unicode 表情符号(例如 "👀")。
    • 使用 "" 可禁用某个渠道或账号的回应。
    来自 Telegram 事件和命令的配置写入

    渠道配置写入默认启用(configWrites !== false)。

    Telegram 触发的写入包括:

    • 群组迁移事件(migrate_to_chat_id)用于更新 channels.telegram.groups
    • /config set/config unset(需要启用命令)

    禁用:

    json5
    {channels: {telegram: {  configWrites: false,},},}
    长轮询与 webhook

    默认是长轮询。对于 webhook 模式,请设置 channels.telegram.webhookUrlchannels.telegram.webhookSecret;可选项包括 webhookPathwebhookHostwebhookPort(默认值为 /telegram-webhook127.0.0.18787)。

    在长轮询模式下,OpenClaw 仅在更新成功分发后才持久化其重启水位线。如果处理器失败,该更新会在同一进程中保持可重试状态,并且不会被写入为已完成以用于重启去重。

    本地监听器绑定到 127.0.0.1:8787。对于公共入口,请在本地端口前放置反向代理,或有意设置 webhookHost: "0.0.0.0"

    Webhook 模式会在向 Telegram 返回 200 之前验证请求防护、Telegram 密钥令牌和 JSON 正文。 然后 OpenClaw 会通过与长轮询相同的按聊天/按话题机器人通道异步处理更新,因此缓慢的智能体轮次不会阻塞 Telegram 的投递 ACK。

    限制、重试和 CLI 目标
    • channels.telegram.textChunkLimit 默认值为 4000。
    • channels.telegram.chunkMode="newline" 会在按长度拆分前优先使用段落边界(空行)。
    • channels.telegram.mediaMaxMb(默认 100)限制入站和出站 Telegram 媒体大小。
    • channels.telegram.mediaGroupFlushMs(默认 500)控制 Telegram 相册/媒体组在 OpenClaw 将其作为一条入站消息分发前缓冲多长时间。如果相册部分到达较晚,请增大该值;如果要降低相册回复延迟,请减小该值。
    • channels.telegram.timeoutSeconds 会覆盖 Telegram API 客户端超时(如果未设置,则使用 grammY 默认值)。机器人客户端会将低于 60 秒出站文本/输入状态请求防护的配置值进行钳制,这样 grammY 就不会在 OpenClaw 的传输防护和回退运行之前中止可见回复投递。长轮询仍使用 45 秒的 getUpdates 请求防护,因此空闲轮询不会被无限期放弃。
    • channels.telegram.pollingStallThresholdMs 默认值为 120000;仅在误报轮询停滞重启时,在 30000600000 之间调整。
    • 群组上下文历史使用 channels.telegram.historyLimitmessages.groupChat.historyLimit(默认 50);0 会禁用。
    • 当 Gateway 网关已观察到父消息时,回复/引用/转发的补充上下文会被规范化到一个选定的对话上下文窗口中;已观察消息缓存会与会话存储一起持久化。Telegram 在更新中只包含一个浅层 reply_to_message,因此早于缓存的链条受限于 Telegram 当前的更新载荷。
    • Telegram 允许列表主要用于限制谁可以触发智能体,并不是完整的补充上下文脱敏边界。
    • 私信历史控制:
      • channels.telegram.dmHistoryLimit
      • channels.telegram.dms["<user_id>"].historyLimit
    • channels.telegram.retry 配置适用于 Telegram 发送辅助函数(CLI/工具/动作)中可恢复的出站 API 错误。入站最终回复投递也会针对 Telegram 预连接失败使用有界安全发送重试,但不会重试可能导致可见消息重复的模糊发送后网络信封。

    CLI 和消息工具发送目标可以是数字聊天 ID、用户名或论坛话题目标:

    bash
    openclaw message send --channel telegram --target 123456789 --message "hi"openclaw message send --channel telegram --target @name --message "hi"openclaw message send --channel telegram --target -1001234567890:topic:42 --message "hi topic"

    Telegram 投票使用 openclaw message poll,并支持论坛话题:

    bash
    openclaw message poll --channel telegram --target 123456789 \--poll-question "Ship it?" --poll-option "Yes" --poll-option "No"openclaw message poll --channel telegram --target -1001234567890:topic:42 \--poll-question "Pick a time" --poll-option "10am" --poll-option "2pm" \--poll-duration-seconds 300 --poll-public

    仅 Telegram 可用的投票标志:

    • --poll-duration-seconds(5-600)
    • --poll-anonymous
    • --poll-public
    • --thread-id 用于论坛话题(或使用 :topic: 目标)

    Telegram 发送还支持:

    • channels.telegram.capabilities.inlineButtons 允许时,使用带有 buttons 块的 --presentation 创建内联键盘
    • 使用 --pin--delivery '{"pin":true}' 在机器人可以在该聊天中固定消息时请求固定投递
    • 使用 --force-document 将出站图片、GIF 和视频作为文档发送,而不是作为压缩照片、动画媒体或视频上传发送

    动作门控:

    • channels.telegram.actions.sendMessage=false 会禁用出站 Telegram 消息,包括投票
    • channels.telegram.actions.poll=false 会禁用 Telegram 投票创建,同时保留常规发送功能
    Telegram 中的 Exec 审批

    Telegram 支持在审批者私信中进行 Exec 审批,也可以选择在原始聊天或话题中发布提示。审批者必须是数字 Telegram 用户 ID。

    配置路径:

    • channels.telegram.execApprovals.enabled(当至少一个审批者可解析时自动启用)
    • channels.telegram.execApprovals.approvers(回退到来自 commands.ownerAllowFrom 的数字所有者 ID)
    • channels.telegram.execApprovals.targetdm(默认)| channel | both
    • agentFiltersessionFilter

    channels.telegram.allowFromgroupAllowFromdefaultTo 控制谁可以与机器人交谈,以及机器人在哪里发送常规回复。它们不会让某人成为 Exec 审批者。当还没有命令所有者时,第一个获批的私信配对会引导生成 commands.ownerAllowFrom,因此单所有者设置仍可工作,无需在 execApprovals.approvers 下重复 ID。

    渠道投递会在聊天中显示命令文本;仅在受信任的群组/话题中启用 channelboth。当提示落在论坛话题中时,OpenClaw 会为审批提示和后续消息保留该话题。Exec 审批默认在 30 分钟后过期。

    内联审批按钮还需要 channels.telegram.capabilities.inlineButtons 允许目标表面(dmgroupall)。带有 plugin: 前缀的审批 ID 会通过插件审批解析;其他 ID 会先通过 Exec 审批解析。

    请参阅 Exec 审批

    错误回复控制

    当 agent 遇到投递或提供商错误时,Telegram 可以回复错误文本,也可以抑制该错误。两个配置键控制此行为:

    默认值 说明
    channels.telegram.errorPolicy reply, silent reply reply 会向聊天发送一条友好的错误消息。silent 会完全抑制错误回复。
    channels.telegram.errorCooldownMs number (ms) 60000 向同一聊天发送错误回复之间的最短时间。防止故障期间产生错误垃圾消息。

    支持按账户、按群组和按主题覆盖(继承方式与其他 Telegram 配置键相同)。

    json5
    {  channels: {    telegram: {      errorPolicy: "reply",      errorCooldownMs: 120000,      groups: {        "-1001234567890": {          errorPolicy: "silent", // suppress errors in this group        },      },    },  },}

    故障排除

    机器人不响应非提及的群组消息
    • 如果 requireMention=false,Telegram 隐私模式必须允许完全可见性。
      • BotFather:/setprivacy -> Disable
      • 然后将机器人从群组中移除并重新添加
    • 当配置预期接收未提及的群组消息时,openclaw channels status 会发出警告。
    • openclaw channels status --probe 可以检查明确的数字群组 ID;通配符 "*" 无法探测成员资格。
    • 快速会话测试:/activation always
    机器人完全看不到群组消息
    • channels.telegram.groups 存在时,群组必须列出(或包含 "*"
    • 验证机器人在群组中的成员资格
    • 查看日志:openclaw logs --follow 以了解跳过原因
    命令部分可用或完全不可用
    • 授权你的发送者身份(配对和/或数字 allowFrom
    • 即使群组策略为 open,命令授权仍然适用
    • setMyCommands failed 并出现 BOT_COMMANDS_TOO_MUCH 表示原生命令菜单条目过多;减少插件/技能/自定义命令,或禁用原生菜单
    • deleteMyCommands / setMyCommands 启动调用和 sendChatAction 输入状态调用都有边界限制,并会在请求超时时通过 Telegram 的传输回退重试一次。持续的网络/获取错误通常表示到 api.telegram.org 的 DNS/HTTPS 可达性问题
    启动报告未授权令牌
    • getMe returned 401 是已配置机器人令牌的 Telegram 身份验证失败。
    • 在 BotFather 中重新复制或重新生成机器人令牌,然后更新默认账户的 channels.telegram.botTokenchannels.telegram.tokenFilechannels.telegram.accounts.<id>.botTokenTELEGRAM_BOT_TOKEN
    • 启动期间的 deleteWebhook 401 Unauthorized 也是身份验证失败;将其视为“没有 webhook 存在”只会把同一个错误令牌失败推迟到之后的 API 调用。
    轮询或网络不稳定
    • Node 22+ + 自定义 fetch/proxy 在 AbortSignal 类型不匹配时可能触发立即中止行为。
    • 某些主机会先将 api.telegram.org 解析为 IPv6;损坏的 IPv6 出站可能导致间歇性 Telegram API 失败。
    • 如果日志包含 TypeError: fetch failedNetwork request for 'getUpdates' failed!,OpenClaw 现在会将这些作为可恢复的网络错误重试。
    • 在轮询启动期间,OpenClaw 会为 grammY 复用成功的启动 getMe 探测,因此 runner 不需要在第一次 getUpdates 前再执行第二次 getMe
    • 如果 deleteWebhook 在轮询启动期间因瞬时网络错误失败,OpenClaw 会继续进入长轮询,而不是再发起另一个预轮询控制平面调用。仍处于活动状态的 webhook 会表现为 getUpdates 冲突;随后 OpenClaw 会重建 Telegram 传输并重试 webhook 清理。
    • 如果 Telegram 套接字按较短的固定周期回收,请检查是否存在过低的 channels.telegram.timeoutSeconds;机器人客户端会将低于出站和 getUpdates 请求保护值的配置值钳制到保护值之上,但旧版本在该值低于这些保护值时可能会中止每次轮询或回复。
    • 如果日志包含 Polling stall detected,OpenClaw 默认会在 120 秒内没有完成长轮询活跃性后重启轮询并重建 Telegram 传输。
    • openclaw channels status --probeopenclaw doctor 会在以下情况发出警告:正在运行的轮询账户在启动宽限期后尚未完成 getUpdates;正在运行的 webhook 账户在启动宽限期后尚未完成 setWebhook;或最近一次成功的轮询传输活动已过期。
    • 仅当长时间运行的 getUpdates 调用健康、但你的主机仍报告误报的轮询停滞重启时,才提高 channels.telegram.pollingStallThresholdMs。持续停滞通常指向主机与 api.telegram.org 之间的代理、DNS、IPv6 或 TLS 出站问题。
    • Telegram 的 Bot API 传输也遵循进程代理环境变量,包括 HTTP_PROXYHTTPS_PROXYALL_PROXY 及其小写变体。NO_PROXY / no_proxy 仍可绕过 api.telegram.org
    • 如果通过服务环境中的 OPENCLAW_PROXY_URL 配置了 OpenClaw 托管代理,且没有标准代理环境变量,则 Telegram 也会将该 URL 用于 Bot API 传输。
    • 在直接出站/TLS 不稳定的 VPS 主机上,通过 channels.telegram.proxy 路由 Telegram API 调用:
    yaml
    channels:telegram:proxy: socks5://<user>:<password>@proxy-host:1080
    • Node 22+ 默认使用 autoSelectFamily=true(WSL2 除外)。Telegram DNS 结果顺序依次遵循 OPENCLAW_TELEGRAM_DNS_RESULT_ORDERchannels.telegram.network.dnsResultOrder,然后是进程默认值,例如 NODE_OPTIONS=--dns-result-order=ipv4first;如果都不适用,Node 22+ 会回退到 ipv4first
    • 如果你的主机是 WSL2,或明确在仅 IPv4 行为下表现更好,请强制选择地址族:
    yaml
    channels:telegram:network:  autoSelectFamily: false
    • RFC 2544 基准测试范围应答(198.18.0.0/15)默认已允许 用于 Telegram 媒体下载。如果受信任的 fake-IP 或 透明代理在媒体下载期间将 api.telegram.org 重写为其他 私有/内部/特殊用途地址,你可以选择启用 仅限 Telegram 的绕过:
    yaml
    channels:telegram:network:  dangerouslyAllowPrivateNetwork: true
    • 同一选择性启用也可按账户在 channels.telegram.accounts.<accountId>.network.dangerouslyAllowPrivateNetwork 中配置。
    • 如果你的代理将 Telegram 媒体主机解析到 198.18.x.x,请先保持 该危险标志关闭。Telegram 媒体默认已经允许 RFC 2544 基准测试范围。
    • 环境变量覆盖(临时):
      • OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1
      • OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1
      • OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first
    • 验证 DNS 应答:
    bash
    dig +short api.telegram.org Adig +short api.telegram.org AAAA

    更多帮助:渠道故障排除

    配置参考

    主要参考:Configuration reference - Telegram

    高信号 Telegram 字段
    • 启动/身份验证:enabledbotTokentokenFileaccounts.*tokenFile 必须指向常规文件;符号链接会被拒绝)
    • 访问控制:dmPolicyallowFromgroupPolicygroupAllowFromgroupsgroups.*.topics.*、顶层 bindings[]type: "acp"
    • Exec 审批:execApprovalsaccounts.*.execApprovals
    • 命令/菜单:commands.nativecommands.nativeSkillscustomCommands
    • 线程/回复:replyToModedm.threadRepliesdirect.*.threadReplies
    • 流式传输:streaming(预览)、streaming.preview.toolProgressblockStreaming
    • 格式化/投递:textChunkLimitchunkModelinkPreviewresponsePrefix
    • 媒体/网络:mediaMaxMbmediaGroupFlushMstimeoutSecondspollingStallThresholdMsretrynetwork.autoSelectFamilynetwork.dangerouslyAllowPrivateNetworkproxy
    • 自定义 API 根地址:apiRoot(仅 Bot API 根地址;不要包含 /bot&lt;TOKEN&gt;
    • webhook:webhookUrlwebhookSecretwebhookPathwebhookHost
    • 操作/能力:capabilities.inlineButtonsactions.sendMessage|editMessage|deleteMessage|reactions|sticker
    • 表情回应:reactionNotificationsreactionLevel
    • 错误:errorPolicyerrorCooldownMs
    • 写入/历史:configWriteshistoryLimitdmHistoryLimitdms.*.historyLimit

    相关内容

    Was this useful?