一个 type guard、一则 PR、一次 merge。从用户到贡献者。
用 OpenClaw 也好一阵子了。每天跟 Pingu 在终端里协作,从写文章、管项目、跑 cron、到整理健康数据,数位生活有一半是在 OpenClaw 里完成的。
用久了,自然会踩到一些边角的 bug。
遇到 Bug
这个 bug 出现在 Telegram 整合的部分。OpenClaw 有个 describeReplyTarget 函数,负责解析 Telegram 消息的 reply context,就是回复一则消息时,被回复那则消息的内容。
问题在于,Telegram API 返回的 replyLike.text 不一定是字串,有时候会是一个 ExternalReplyInfo 对象。但原本的代码直接对它调用 .trim():
const rawText = replyLike.text ?? replyLike.caption ?? "";
return rawText.trim(); // 如果 rawText 是对象 → TypeError
对象没有 .trim() 方法,直接 TypeError 炸开。
修复
修法很简单,一个 type guard:
const rawText = replyLike.text ?? replyLike.caption ?? "";
const safeText = typeof rawText === "string" ? rawText.trim() : "";
同一个函数里,quoteText 其实已经用了一模一样的 pattern。这次的修改就是把已有的防御逻辑补到漏掉的地方。
顺手补了一个 regression test,确保非字串值不会再炸:
// 传入 text: { some: "object" } → 应该返回 null,不是 throw
PR 提交
PR #50500,标题:
fix(telegram): add type guard for reply context text
提交之后,Greptile(自动 code review bot)给了 5/5 confidence:
“This PR is safe to merge:the change is minimal, correct, and well-tested.”
Maintainer @obviyus 在 3/23 直接 merge 进 main,留了一句:
“Thanks @p3nchan.”
没有来回修改,没有 request changes,一发就中。
感想
这是第一次对一个有规模的开源项目提交 PR 并被 merge。
改动很小,就是一个 type guard、几行代码。但从「用户」变成「贡献者」,身份转换的感觉比代码本身重要太多了。
好的开源贡献往往就是这样。在日常使用中发现问题,然后顺手修掉,比惊天动地的重构更实际。
每天在用的工具,里面可能就有一个小小的 bug 等着被修。
认真玩,慢慢来。
延伸阅读
小企鹅的经验
OpenClaw 是每天会用到的核心工具,从写文章、管项目到跑 cron 都靠它。用久了自然会踩到边角的 bug,这次 Telegram reply context 的 type 问题就是日常用着用着被触发的。第一次送 PR 给有规模的开源项目,本来预期会来回修很多次,结果一发就中,反而有点意外。顺手修自己用得到的东西,这条路径比想像中顺。
常见问题
Q: OpenClaw 是什么?
OpenClaw 是一个开源的 AI CLI 工具,可以在终端中与 AI 互动,执行代码、管理文件、自动化工作流程。
Q: 这个 PR 修了什么问题?
修复了 Telegram 平台上 reply context text 的 runtime error。当 API 返回非字串值时,原本的 .trim() 会直接炸掉,加了一个 type guard 就解决了。
Q: 第一次贡献开源项目难吗?
不难,但要找到对的切入点。从自己实际遇到的 bug 出发,修复自然顺手,reviewer 也容易理解动机。
整理:Penna|小企鹅 Penchan