ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenClaw Telegram 端到端验证:用真实用户驱动 basic-turns 证明 DM、群组与原生命令三条消息链路

OpenClaw Telegram 端到端验证:用真实用户驱动 basic-turns 证明 DM、群组与原生命令三条消息链路 OpenClaw Telegram 端到端验证用真实用户驱动 basic-turns 证明 DM、群组与原生命令三条消息链路【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw本篇技术指南围绕 OpenClaw 仓库中 basic-turns 验证配方 展开讲解如何借助 Telegram E2E Userbot 测试装置runner TDLib 真实用户驱动 确定性 mock provider以真实 QA 用户的身份在 Telegram Test Server 上证明三类基本回合basic turns私聊直发DM、群内 提及、原生斜杠命令。读完本文你将掌握 runner 的完整命令行用法、summary.json与mock-openai-requests.ndjson的证据判定标准以及如何用同一套装置把用户能触达 bot、模型响应能回到同一会话验证为可复现、可引用的工程事实。一、basic-turns 在验证体系中的定位在 OpenClaw 的 Telegram 端到端验证体系中features/README.md 验证地图 是证明 OpenClaw Telegram 用户可见行为的维护入口而 basic-turns 是其中最基础的验证条目。它的核心目标用一句话概括Basic turns prove that a dedicated Telegram user can reach the OpenClaw bot and receive the deterministic provider response in the same chat.即一个专属的 Telegram 真实用户账户能够触达 OpenClaw bot并在同一个会话中收到确定性的 provider 响应。所谓确定性是因为该链路中的模型由仓库自带的 mock-openai-server.mjs 扮演——它不依赖真实模型而是按请求内容回显约定的标记字符串从而让验证结果可预测、可复现。basic-turns 拆分为三个子特性sub-features覆盖三条不同的消息入口子特性说明对应消息形态turn-dm发送一条隔离的私聊直发回合直接打开 bot 私聊发送普通消息turn-group发送一条 提及目标 bot 的群组回合在 QA 群内 bot 后发送普通消息turn-command发送一条指向被测 botSUT的原生斜杠命令在 QA 群内发送/statusbot username为什么这套装置坚持用真实用户TDLib user driver而不是第二个 botSKILL.md 给出了明确理由用户驱动能看到编辑、删除、反应和正在输入typing等第二个 bot 无法观测的事件。验证证据是一份结构化的 Telegram 事件时间线event timeline而不是笼统的通了/没通。二、运行前置条件Preconditionsbasic-turns 是运行在整套 userbot 装置之上的配方因此在驱动任何回合前必须满足以下前置条件基线 doctor 通过运行 telegram-test-doctor.mjs要求返回ok: true。doctor 会租借一个凭证、恢复其私有 TDLib 状态、确认 Test Server 上固定的 TDLib 版本、经 Test Bot API 代理验证 SUT bot随后移除状态并释放租约。QA 用户与 SUT bot 之间已存在直接会话DM 路径要求两者共享私聊群组路径使用配置好的 QA 群。在 OpenClaw checkout 目录下先准备环境变量来自 SKILL.mdTELEGRAM_E2E_SKILL_DIR${TELEGRAM_E2E_SKILL_DIR:-$PWD/.agents/skills/telegram-e2e-userbot} export TELEGRAM_E2E_SKILL_DIR # 共享主机上每次运行使用两个未占用的端口 : ${TELEGRAM_GATEWAY_PORT:?set an unused Gateway port} : ${TELEGRAM_MOCK_PORT:?set an unused provider port} export TELEGRAM_GATEWAY_PORT TELEGRAM_MOCK_PORT凭证通过 Convex 凭证池租借qa/convex-credential-broker每个凭证包含一个 SUT bot和一个独立的 TDLib 授权两者共享同一个 QA 用户身份独立授权可避免并行运行时 Telegram 更新在多个观察者之间被拆分。runner 持有租约期间独占该凭证运行结束清理时释放。三、用户视角的三种进入方式配方首先从真实用户会怎么操作的角度定义了三条路径user POV打开 bot 的私聊发送一条普通消息 → 对应turn-dm打开 QA 群 提及 bot 后发送一条普通消息 → 对应turn-group打开 QA 群发送/statusbot username→ 对应turn-command。这三条路径被映射为 runner 的三种驱动模式--dm私聊、无--dm的{sut}文本群组提及、/status{sut}文本原生命令。注意群组路径中{sut}是必需的——这正是 Gotchas 中强调的群组提示词需要{sut}群组原生命令需要/status{sut}。四、用 userbot runner 驱动三种 basic turn所有回合都通过同一个规范入口驱动run-mock-sut-user-e2e.mjs。该 runner 自行负责租借一个 Convex 凭证、启动 Test Bot API 代理、拉起一个全新 SUT gateway、启动选定的 provider、执行真实用户动作、录制证据、拆除并清理。4.1 驱动一个 DM 回合turn-dmmkdir -p $TELEGRAM_E2E_PROOF_DIR/basic-turns node $TELEGRAM_E2E_SKILL_DIR/scripts/run-mock-sut-user-e2e.mjs \ --dm --timeout-ms 25000 \ --text Please answer with OPENCLAW_E2E_BASIC only. \ --record $TELEGRAM_E2E_PROOF_DIR/basic-turns/events.ndjson \ --output $TELEGRAM_E2E_PROOF_DIR/basic-turns/summary.json参数拆解--dm以私聊模式直发 SUT botrunner 内部会解析为{sut}的私聊选择器见 scenario.mjs 的 selectChatTarget--timeout-ms 25000回合超时默认值为60000源码parseArgs中的timeoutMs: 60_000--text Please answer with OPENCLAW_E2E_BASIC only.QA 用户实际发送的文本其中携带了验证标记OPENCLAW_E2E_BASIC--record录制模式产出events.ndjson事件时间线录制模式拒绝--expect/--any-sut-reply这类探针断言只捕获事实--output产出归一化的summary.json摘要。判定标准summary.json必须包含发送的消息sentAction/sentMessageIds、至少一条 SUT 消息且sutRevisionTexts中必须包含OPENCLAW_E2E_BASIC。也就是说mock provider 回显的标记必须作为 SUT 的回复文本被真实用户观测到。边界确认boundary要求mock-openai-requests.ndjson中至少存在一行POST /v1/responses。这里的逻辑是真实的 Telegram 事件TDLib 观测与 provider 请求mock 服务器记录加在一起才能证明这条回合同时跨越了两条边界——Telegram 入站边界与模型 provider 出站边界。缺任何一边都不算数。4.2 驱动一个群组回合turn-groupmkdir -p $TELEGRAM_E2E_PROOF_DIR/basic-group node $TELEGRAM_E2E_SKILL_DIR/scripts/run-mock-sut-user-e2e.mjs \ --timeout-ms 25000 \ --text {sut} Please answer with OPENCLAW_E2E_GROUP only. \ --record $TELEGRAM_E2E_PROOF_DIR/basic-group/events.ndjson \ --output $TELEGRAM_E2E_PROOF_DIR/basic-group/summary.json与 DM 回合的区别在于不传--dm文本以{sut}开头对 SUT bot 做提及。判定标准发送的群组消息存在、SUT 回复中包含OPENCLAW_E2E_GROUP、且恰好记录到一条模型请求。群组路径还会经过 runner 写入的群组策略配置groupPolicy: allowlist、groupAllowFrom: [testerId]、可选requireMention因此它顺带验证了群组提及策略下的入站处理。4.3 驱动一个原生命令回合turn-commandmkdir -p $TELEGRAM_E2E_PROOF_DIR/basic-command node $TELEGRAM_E2E_SKILL_DIR/scripts/run-mock-sut-user-e2e.mjs \ --timeout-ms 25000 --text /status{sut} \ --record $TELEGRAM_E2E_PROOF_DIR/basic-command/events.ndjson \ --output $TELEGRAM_E2E_PROOF_DIR/basic-command/summary.json判定标准与前两者截然相反要求 SUT 返回一条状态回复且mock-openai-requests.ndjson为空。原因是/status是 OpenClaw 的原生命令快路径——它在模型执行之前就作答根本不产生 provider 请求。runner 生成的临时配置中channels.telegram.commands被设为{ native: true, nativeSkills: false }正是为了开启这条原生命令通道见 run-mock-sut-user-e2e.mjs 的 writeConfig。五、证据模型与判定标准基本回合的证据由两类产物组成理解它们的字段含义是正确判定的前提。5.1 summary.json 归一化摘要user-record.py 在录制结束时产出摘要关键字段包括sentAction/sentMessageId(s)本次驱动发送的动作与消息 ID是证据时间线的起点sutTotals按事件类型统计的 SUT 消息计数message/edit/delete等sutRevisionTextsSUT 各修订版本的消息文本——basic-turns 用它在回复中寻找OPENCLAW_E2E_BASIC/OPENCLAW_E2E_GROUP标记totals、recordingComplete、timeline总计数、录制完成标志、归一化事件时间线。时间线行示例来自 运行时参考 的证据模型{ recordingComplete: true, totals: { message: 1, edit: 2, delete: 1 }, sutTotals: { message: 1, edit: 2, delete: 1 }, timeline: [{ elapsedMs: 8159, kind: message, botApiMessageId: 46145, isSut: true }] }事件kind取值为message、edit、edit-meta、delete、typing或reaction。消息/编辑行携带 SUT 身份、回复目标、引用文本、主题、内容类型与提取出的富文本反应行携带 emoji 与计数。botApiMessageId是录制器对观测账户服务端消息 IDmessageId 20的历史命名用于跨消息、编辑、反应、删除事件做稳定关联。5.2 mock-openai-requests.ndjson provider 请求日志mock-openai-server.mjs 把每一次 provider 请求以 NDJSON 追加到该文件每条记录含seq绝对序号、method、path/v1/responses或/v1/chat/completions、请求体摘要与内容事实。provider 请求数是判定回合是否真正抵达模型的硬指标DM/群组普通回合要求 ≥1原生命令要求 0。5.3 证据判定的一般原则来自 SKILL.md 的判定证据章节从summary.json中的发送动作开始只判断所选 SUT 的后续事件用稳定的botApiMessageId串联消息、编辑、反应与删除路径应当到达模型时必须有 provider 请求原生命令正确地可以没有。TDLib 会在连接后重放缓存的更新因此只判定本次发送动作之后的事件运行时参考。六、源码级原理runner 与 mock provider 如何协作6.1 runner 生成一次性被测环境每次运行runner 都会在临时目录生成一套独立的 gateway 配置writeConfig见 run-mock-sut-user-e2e.mjs关键点包括gatewaymode: local、绑定 loopback、auth: { mode: none }端口来自--gateway-port默认19879logging.file把 gateway 日志收拢到本次运行专属的gateway.log避免与共享的/tmp/openclaw/date.log混流models.providers.openaibaseUrl指向http://127.0.0.1:mock-port/v1默认19882模型为gpt-5.5并开启request.allowPrivateNetwork——这正是401 来自 api.openai.com 意味着没走 mock 地址的排查依据channels.telegramdmPolicy/groupPolicy均为 allowlistallowFrom/groupAllowFrom仅含 tester 身份commands: { native: true, nativeSkills: false }群组可按E2E_REQUIRE_MENTION开启requireMentionmessages.groupChat.visibleReplies: automatic控制群内回复可见性。配置可被环境变量补丁覆盖见 验证地图 的非默认配置表E2E_TELEGRAM_CONFIG_PATCH覆盖channels.telegram下的任意键E2E_ROOT_CONFIG_PATCH覆盖配置根如messages.*E2E_TELEGRAM_PROVIDER_API切换openai-completions等传输形态--source-gateway则直接用 TS 源码启动而不依赖构建产物。6.2 mock provider 的标记回显机制mock 服务器默认的成功标记是SUCCESS_MARKER环境变量默认OPENCLAW_E2E_OKrunner 会把它设为E2E_TELEGRAM_MOCK_RESPONSE。更精确的机制在 mock-openai-server.mjs 的 resolveResponseText 中它扫描请求体中的OPENCLAW_E2E_[A-Z0-9_]标记并回显最后一个匹配项。这就是为什么--text里写OPENCLAW_E2E_BASIC、OPENCLAW_E2E_GROUPSUT 回复就能确定性地包含同一标记——模型行为被替换为可预测的文本回显验证因此完全确定。响应以 SSE 流式输出response.output_text.delta等事件模拟真实流式传输路径。6.3 启动与就绪检查runner 依次等待mock 服务器输出mock-openai listening10 秒、gateway 的/readyz通过默认 45 秒--source-gateway时为 300 秒。驱动前还会执行drainSutUpdates清理 SUT bot 上残留的 webhook 与待处理更新保证回合从干净状态开始。6.4 清理与脱敏runner 只停止自己派生的进程组移除凭证与 gateway 的临时 scratch 状态但显式指定的证明目录proof directory会被保留。runner 通过sanitizeChildEnvironment过滤子进程环境中的密钥如BWS_、GITHUB_、OPENCLAW_QA_CONVEX_前缀及含SECRET/TOKEN/PASSWORD等键名并在输出日志中对 bot token、用户 ID、用户名、临时路径做redacted替换。凭证只允许存在于来源、活跃租约或私有 runner scratch 中证据离开本地任务时必须对 bot id 与用户名脱敏。七、runner 参数速查以下参数来自 run-mock-sut-user-e2e.mjs 的 parseArgs含默认值参数作用默认值--text text驱动回合的发送文本{sut} Please answer with OPENCLAW_E2E_OK only.--dm私聊模式直发 SUT bot关闭群组模式--timeout-ms ms回合超时60000--record path录制事件时间线 NDJSON禁止与--expect/--any-sut-reply同用无--output path归一化摘要 JSON临时目录内probe-result.json--gateway-port port被测 gateway 端口19879--mock-port portmock provider 端口19882--backend namemock确定性回显/qa-mockQA 工具夹具/claude-cli真实 Claude CLI默认模型claude-haiku-4-5可用E2E_TELEGRAM_CLI_MODEL覆盖mock--expect text探针模式断言无--record时可用OPENCLAW_E2E_OK--any-sut-reply探针模式接受任意 SUT 回复关闭--chat target指定会话TDLib chat id /username/ 邀请链接 /t.me链接由--dm或租约群组解析--pre-send text驱动前由 QA 用户预发消息历史作用域场景无--photo path图片/相册回合可重复传入组成一个媒体相册无--scenario path运行 JSON 场景动作列表需--record无--source-gateway直接运行 TS checkout不构建 dist关闭探针模式无--record适合快速核对回复录制模式--record才产出可归档、可审查的证明文件集events.ndjson、summary.json、gateway.log、mock-openai-requests.ndjson、sut-config.jsonrunner 会把本次使用的配置副本拷入证明目录便于复盘。八、Gotchas 与故障排查8.1 原配方的四条 Gotchas务必逐条遵守共享群组包含无关流量群组里所有隐私关闭的池内 bot 都能看到消息。除非要验证的正是群组策略mention、命令、话题、反应否则优先--dm隔离回合。群组提示词需要{sut}群组原生命令需要/status{sut}两种形态的定位语法不同混用会打不中目标。模型请求证据只适用于普通回合原生/status用零请求证明其快路径——没有 provider 请求恰恰是它的正确证据形态。保留证明产物runner 会移除其 scratch gateway 状态但显式指定的--record/--output文件会保留需在审查/复现完成前一直保存。8.2 无 SUT 回复时的五层边界排查运行时参考 给出了按顺序排查的边界清单凭证恢复成功status --json报告testDc: true且 TDLib 版本为1.8.67runner 固定prebuilt-tdlib包0.1008067.0SUT 的 Test Bot API 无 webhook、无陈旧 pending updatesdrainSutUpdates负责此项gateway 日志显示已选中的 Telegram provider 与一条入站 updatemock-openai-requests.ndjson中存在预期 provider 请求gateway 日志包含发往同一会话的出站发送。零条 provider 请求 回合从未抵达模型api.openai.com返回401 gateway 没有使用 mock base URL出站发送存在但观测不到回复 问题在 TDLib 授权或会话选择而非模型。另外注意gateway 日志不能证明编辑 vs 发送的区别这类判定必须依赖 TDLib 事件。九、与其他 feature 的衔接basic-turns 只覆盖基本回合同一装置下的其他配方共同构成完整的 Telegram 用户可见行为验证delivery-lifecycle.md消息、编辑、正在输入与回执完成态claim 与所需事实的映射见 运行时参考连续edit行证明草稿演进、同一 id 上的最终edit证明替换、后续delete证明草稿移除、typing行证明回复前有输入状态reaction-lifecycle.md作用于用户消息上的确认/状态反应注意Telegram 只对 QA 用户自己发送的消息推送反应更新bot 对自己消息的反应不可见图片/相册回合传--photo PATH重复传入组成一个媒体相册检查messagePhoto事件与 provider 证据。从验证地图的驱动约定看所有配方共用同一条纪律每个 feature 使用独立的证明子目录、显式的--record/--output路径一次驱动失败后下一次 Telegram 动作前必须重跑 doctor。basic-turns 正是这条纪律下最基础、最适合作为回归基准的一组证据。十、小结basic-turns 以真实用户 确定性 provider的组合把 OpenClaw Telegram 通道最核心的三条消息链路变成了可机械判定的事实DM 私聊、群组提及、原生命令。普通回合用真实 Telegram 事件 provider 请求日志双重证据证明消息跨过两条边界并回到同一会话原生/status则用零请求 状态回复证明快路径。配合--record/--output落盘的证明目录与 runner 的自动清理、脱敏与租约管理这套验证可以在任何依赖就绪的 checkout 上重复执行为 Telegram 通道的每次变更提供用户视角的回归保障。【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表