消息平台

Telegram

可用于生产环境的机器人私信和群组,基于 grammY。长轮询是默认模式;Webhook 模式是可选的。

快速设置

  • 在 BotFather 中创建机器人令牌

    打开 Telegram 并与 @BotFather 聊天(确认账号名正是 @BotFather)。

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

  • 配置令牌和私信策略

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

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

  • 启动 Gateway 网关并批准第一条私信

    openclaw gateway
    openclaw pairing list telegram
    openclaw pairing approve telegram <CODE>
    

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

  • 将机器人添加到群组

    将机器人添加到你的群组,然后设置 channels.telegram.groupsgroupPolicy,使其匹配你的访问模型。

  • Telegram 侧设置

    隐私模式和群组可见性

    Telegram 机器人默认使用隐私模式,这会限制它们能接收哪些群组消息。

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

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

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

    群组权限

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

    管理员机器人会接收所有群组消息,这对始终在线的群组行为很有用。

    有用的 BotFather 开关
    • /setjoingroups 用于允许/拒绝添加到群组
    • /setprivacy 用于群组可见性行为

    访问控制和激活

    私信策略

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

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

    dmPolicy: "open" 搭配 allowFrom: ["*"] 会允许任何找到或猜到机器人用户名的 Telegram 账号向机器人发送命令。仅对有意公开、且工具受到严格限制的机器人使用它;单所有者机器人应使用带数字用户 ID 的 allowlist

    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,让仅所有者命令和执行批准拥有显式操作员账号。 群组发送者授权仍来自显式配置允许列表。 如果你想要“我授权一次后,私信和群组命令都能工作”,请将你的数字 Telegram 用户 ID 放入 channels.telegram.allowFrom;对于仅所有者命令,请确保 commands.ownerAllowFrom 包含 telegram:<your user id>

    查找你的 Telegram 用户 ID

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

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

    官方 Bot API 方法:

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

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

    群组策略和允许列表

    两个控制项会一起生效:

    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,除非显式设置了 channels.defaults.groupPolicy,否则运行时会默认失败关闭为 groupPolicy="allowlist"

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

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

    示例:只允许一个特定群组内的特定用户:

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

    提及行为

    群组回复默认需要提及。

    提及可以来自:

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

    会话级命令开关:

    • /activation always
    • /activation mention

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

    持久化配置示例:

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

    获取群组聊天 ID:

    • 将群组消息转发给 @userinfobot / @getidsbot
    • 或从 openclaw logs --follow 中读取 chat.id
    • 或检查 Bot API getUpdates

    运行时行为

    • Telegram 由 Gateway 网关进程拥有。
    • 路由是确定性的:Telegram 入站会回复到 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 网关、脚本或外部轮询器正在使用同一个令牌。
    • 长轮询看门狗默认会在 120 秒没有完成 getUpdates 活性检查后触发重启。只有当你的部署在长时间运行的工作期间仍然出现误报的轮询停滞重启时,才增加 channels.telegram.pollingStallThresholdMs。该值以毫秒为单位,允许范围为 30000600000;支持按账号覆盖。
    • Telegram Bot API 不支持已读回执(sendReadReceipts 不适用)。

    功能参考

    实时流式预览(消息编辑)

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

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

    要求:

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

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

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

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

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

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

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

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

    对于纯文本回复:

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

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

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

    仅限 Telegram 的推理流:

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

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

    • 类 Markdown 文本会渲染为 Telegram 安全的 HTML。
    • 原始模型 HTML 会被转义,以减少 Telegram 解析失败。
    • 如果 Telegram 拒绝解析后的 HTML,OpenClaw 会以纯文本重试。

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

    原生命令和自定义命令

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

    原生命令默认值:

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

    添加自定义命令菜单项:

    {
    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 命令可以工作,但 deleteWebhookdeleteMyCommandssetMyCommands404: Not Found 失败时,可能表示 channels.telegram.apiRoot 被设置成了完整的 /bot&lt;TOKEN&gt; 端点。apiRoot 必须只是 Bot API 根地址,openclaw doctor --fix 会移除意外尾随的 /bot&lt;TOKEN&gt;
    • getMe returned 401 表示 Telegram 拒绝了配置的 bot token。请使用当前 BotFather token 更新 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 用于最新请求

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

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

    更多详情:配对

    内联按钮

    配置内联键盘作用域:

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

    按账户覆盖:

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

    作用域:

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

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

    消息动作示例:

    {
    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 路由到不同的智能体。这会让每个话题拥有自己的隔离工作区、记忆和会话。示例:

    {
      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 智能体

    从聊天生成线程绑定的 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]] 来强制发送语音消息
    • 入站语音消息转录会在智能体上下文中被标记为机器生成的、不可信文本;提及检测仍使用原始转录,因此带提及门控的语音消息会继续工作。

    消息操作示例:

    {
    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,
    }
    

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

    贴纸

    入站贴纸处理:

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

    贴纸上下文字段:

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

    贴纸缓存文件:

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

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

    启用贴纸操作:

    {
    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.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(需要启用命令)

    禁用:

    {
    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 密钥令牌和 JSON 正文,然后再向 Telegram 返回 200。 OpenClaw 随后会通过长轮询使用的同一套按聊天/按话题机器人通道异步处理更新,因此缓慢的智能体轮次不会阻塞 Telegram 的投递确认。

    限制、重试和 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 表示禁用。
    • 回复/引用/转发的补充上下文目前会按接收内容传递。
    • Telegram 允许列表主要用于限制谁可以触发智能体,而不是完整的补充上下文脱敏边界。
    • 私信历史控制:
      • channels.telegram.dmHistoryLimit
      • channels.telegram.dms["<user_id>"].historyLimit
    • channels.telegram.retry 配置适用于 Telegram 发送辅助函数(CLI/工具/操作),用于可恢复的出站 API 错误。入站最终回复投递也会针对 Telegram 预连接失败使用有界安全发送重试,但不会重试可能导致可见消息重复的、语义不明确的发送后网络包络。

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

    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,并支持论坛话题:

    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 中的执行审批

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

    配置路径:

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

    channels.telegram.allowFromgroupAllowFromdefaultTo 控制谁可以与机器人对话以及它将普通回复发送到哪里。它们不会让某人成为执行审批者。当尚不存在命令所有者时,第一个获批的私信配对会引导写入 commands.ownerAllowFrom,因此单所有者设置仍可工作,而无需在 execApprovals.approvers 下重复 ID。

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

    内联审批按钮也要求 channels.telegram.capabilities.inlineButtons 允许目标表面(dmgroupall)。以 plugin: 为前缀的审批 ID 会通过插件审批解析;其他 ID 会先通过执行审批解析。

    参见 执行审批

    错误回复控制

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

    默认值 描述
    channels.telegram.errorPolicy reply, silent reply reply 会向聊天发送友好的错误消息。silent 会完全抑制错误回复。
    channels.telegram.errorCooldownMs number (ms) 60000 向同一聊天发送错误回复之间的最短时间。可防止中断期间的错误刷屏。

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

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

    故障排除

    机器人不响应未提及它的群组消息
    • 如果 requireMention=false,Telegram 隐私模式必须允许完全可见。
      • BotFather:/setprivacy -> Disable
      • 然后移除并重新将 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 表示原生命令菜单条目过多;减少插件/技能/自定义命令,或禁用原生命令菜单
    • deleteMyCommands / setMyCommands 启动调用和 sendChatAction 输入状态调用都有边界限制,并且会在请求超时时通过 Telegram 的传输回退重试一次。持续的网络/抓取错误通常表示到 api.telegram.org 的 DNS/HTTPS 可达性问题
    启动报告未授权 token
    • getMe returned 401 是已配置 bot token 的 Telegram 身份验证失败。
    • 在 BotFather 中重新复制或重新生成 bot token,然后为默认账号更新 channels.telegram.botTokenchannels.telegram.tokenFilechannels.telegram.accounts.<id>.botTokenTELEGRAM_BOT_TOKEN
    • 启动期间的 deleteWebhook 401 Unauthorized 也是身份验证失败;将其当作“webhook 不存在”只会把同一个错误 token 失败推迟到后续 API 调用。
    轮询或网络不稳定
    • Node 22+ + 自定义 fetch/proxy 在 AbortSignal 类型不匹配时可能触发立即中止行为。
    • 一些主机会先将 api.telegram.org 解析为 IPv6;损坏的 IPv6 出站可能导致间歇性 Telegram API 失败。
    • 如果日志包含 TypeError: fetch failedNetwork request for 'getUpdates' failed!,OpenClaw 现在会将这些作为可恢复的网络错误重试。
    • 轮询启动期间,OpenClaw 会为 grammY 复用成功的启动 getMe 探测,因此运行器在第一次 getUpdates 前不需要第二次 getMe
    • 如果轮询启动期间 deleteWebhook 因临时网络错误失败,OpenClaw 会继续进入长轮询,而不是再发起一次轮询前控制平面调用。仍然活跃的 webhook 会表现为 getUpdates 冲突;随后 OpenClaw 会重建 Telegram 传输并重试 webhook 清理。
    • 如果 Telegram 套接字按短固定周期回收,检查 channels.telegram.timeoutSeconds 是否过低;bot 客户端会将低于出站和 getUpdates 请求保护值的配置值钳制到保护值以上,但旧版本在该值低于这些保护值时可能每次轮询或回复都会中止。
    • 如果日志包含 Polling stall detected,OpenClaw 默认会在 120 秒没有完成的长轮询活性后重启轮询并重建 Telegram 传输。
    • 当运行中的轮询账号在启动宽限期后还没有完成 getUpdates、运行中的 webhook 账号在启动宽限期后还没有完成 setWebhook,或最近一次成功的轮询传输活动已过期时,openclaw channels status --probeopenclaw doctor 会发出警告。
    • 只有当长时间运行的 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 调用:
    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 行为下工作得更好,请强制协议族选择:
    channels:
    telegram:
    network:
      autoSelectFamily: false
    
    • 默认已经允许 RFC 2544 基准测试范围答案(198.18.0.0/15) 用于 Telegram 媒体下载。如果受信任的 fake-IP 或 透明代理在媒体下载期间将 api.telegram.org 重写为其他 私有/内部/特殊用途地址,你可以选择启用 仅限 Telegram 的绕过:
    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 答案:
    dig +short api.telegram.org A
    dig +short api.telegram.org AAAA
    

    更多帮助:渠道故障排除

    配置参考

    主要参考:配置参考 - Telegram

    高信号 Telegram 字段
    • 启动/身份验证:enabledbotTokentokenFileaccounts.*tokenFile 必须指向常规文件;符号链接会被拒绝)
    • 访问控制:dmPolicyallowFromgroupPolicygroupAllowFromgroupsgroups.*.topics.*、顶层 bindings[]type: "acp"
    • 执行审批: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

    相关