feat(notify): 支持微信Claw - #560
Conversation
审查者指南本 PR 通过新增微信 iLink 与 QQ 官方机器人管理器,将二维码绑定、凭据生命周期、安全存储回退、长消息发送和令牌/会话维护接入后端通知中心;同时扩展通知分发与失败提示、前端扫码配置界面、本地化文案、生成 API 客户端及相关测试。 微信 Claw 二维码绑定和通知发送时序图sequenceDiagram
actor User
participant UI as NotificationSettings
participant API as OpenClawWeixinAPI
participant Manager as OpenClawWeixinManager
participant WeChat as WeChat_iLink
participant Storage as CredentialStorage
User->>UI: start_login()
UI->>API: POST /api/setting/openclaw-weixin/login/start
API->>Manager: start_login()
Manager->>WeChat: get_bot_qrcode()
WeChat-->>Manager: qrcode and qr_url
Manager-->>UI: sessionId and qrUrl
User->>WeChat: Scan QR code
UI->>API: POST /login/check(sessionId, verifyCode)
API->>Manager: check_login(session_id, verify_code)
Manager->>WeChat: get_qrcode_status()
WeChat-->>Manager: confirmed credentials
Manager->>Storage: Save encrypted credentials or runtime fallback
Manager-->>UI: connected
Note over Manager,WeChat: Notification dispatch uses send(title, content)
Manager->>WeChat: sendmessage() for each text chunk
WeChat-->>Manager: delivery result
通过新渠道发送通知的时序图sequenceDiagram
participant Task as TaskNotification
participant Dispatch as NotifyDispatch
participant Notify as NotificationService
participant Weixin as OpenClawWeixinManager
participant QQ as OpenClawQQManager
participant WeChat as WeChat_iLink
participant QQAPI as QQ_OfficialBotAPI
participant UI as TaskActivityView
Task->>Dispatch: dispatch_task_report()
Dispatch->>Notify: send_openclaw_weixin(title, content)
Notify->>Weixin: send(title, content)
Weixin->>WeChat: sendmessage() per text chunk
WeChat-->>Weixin: result
Dispatch->>Notify: send_openclaw_qq(title, content)
Notify->>QQ: send(title, content)
QQ->>QQ: _ensure_access_token()
QQ->>QQAPI: send C2C message per text chunk
QQAPI-->>QQ: result
Dispatch-->>UI: TASK_NOTICE warning when a channel fails
文件级变更
提示和命令与 Sourcery 交互
自定义使用体验访问你的控制面板以:
获取帮助Original review guide in EnglishReviewer's Guide本 PR 通过新增微信 iLink 与 QQ 官方机器人管理器,将二维码绑定、凭据生命周期、安全存储回退、长消息发送和令牌/会话维护接入后端通知中心;同时扩展通知分发与失败提示、前端扫码配置界面、本地化文案、生成 API 客户端及相关测试。 Sequence diagram for WeChat Claw QR binding and notification deliverysequenceDiagram
actor User
participant UI as NotificationSettings
participant API as OpenClawWeixinAPI
participant Manager as OpenClawWeixinManager
participant WeChat as WeChat_iLink
participant Storage as CredentialStorage
User->>UI: start_login()
UI->>API: POST /api/setting/openclaw-weixin/login/start
API->>Manager: start_login()
Manager->>WeChat: get_bot_qrcode()
WeChat-->>Manager: qrcode and qr_url
Manager-->>UI: sessionId and qrUrl
User->>WeChat: Scan QR code
UI->>API: POST /login/check(sessionId, verifyCode)
API->>Manager: check_login(session_id, verify_code)
Manager->>WeChat: get_qrcode_status()
WeChat-->>Manager: confirmed credentials
Manager->>Storage: Save encrypted credentials or runtime fallback
Manager-->>UI: connected
Note over Manager,WeChat: Notification dispatch uses send(title, content)
Manager->>WeChat: sendmessage() for each text chunk
WeChat-->>Manager: delivery result
Sequence diagram for notification dispatch through new channelssequenceDiagram
participant Task as TaskNotification
participant Dispatch as NotifyDispatch
participant Notify as NotificationService
participant Weixin as OpenClawWeixinManager
participant QQ as OpenClawQQManager
participant WeChat as WeChat_iLink
participant QQAPI as QQ_OfficialBotAPI
participant UI as TaskActivityView
Task->>Dispatch: dispatch_task_report()
Dispatch->>Notify: send_openclaw_weixin(title, content)
Notify->>Weixin: send(title, content)
Weixin->>WeChat: sendmessage() per text chunk
WeChat-->>Weixin: result
Dispatch->>Notify: send_openclaw_qq(title, content)
Notify->>QQ: send(title, content)
QQ->>QQ: _ensure_access_token()
QQ->>QQAPI: send C2C message per text chunk
QQAPI-->>QQ: result
Dispatch-->>UI: TASK_NOTICE warning when a channel fails
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
你好——我发现了 2 个问题
AI 代理提示词
请处理此次代码审查中的评论:
## 单独评论
### 评论 1
<location path="app/services/notification.py" line_range="308-309" />
<code_context>
+ "AuthorizationType": "ilink_bot_token",
+ "Authorization": f"Bearer {bot_token}",
+ "X-WECHAT-UIN": base64.b64encode(
+ str(secrets.randbits(32)).encode("ascii")
+ ).decode("ascii"),
+ "iLink-App-Id": "bot",
+ "iLink-App-ClientVersion": OPENCLAW_WEIXIN_CLIENT_VERSION,
</code_context>
<issue_to_address>
**问题 (bug_risk):** `X-WECHAT-UIN` 请求头正在对随机数的 ASCII 十进制表示进行 Base64 编码,但 iLink 协议要求对 32 位无符号整数的二进制字节进行 Base64 编码。网关会拒绝该请求头或无法解析它,因此每个微信消息发送请求都会无法通过协议验证。
**触发条件:** 当 iLink 网关验证必需的 `X-WECHAT-UIN` 请求头时。
**建议修复:** 使用固定宽度的二进制表示来编码该值,例如 `base64.b64encode(struct.pack(">I", secrets.randbits(32))).decode("ascii")`。
</issue_to_address>
### 评论 2
<location path="app/services/notification.py" line_range="268" />
<code_context>
else:
raise Exception(f"ServerChan 推送通知失败: {response.text}")
+ async def send_openclaw_weixin(self, title: str, content: str) -> None:
+ """通过微信公开的 OpenClaw/iLink HTTP 协议推送一条文本通知。
+
+ 这是通知渠道的最小单账号实现:账号登录与会话上下文由配置提供,
+ AUTO-MAS 不启动 OpenClaw 进程,也不负责二维码登录流程。
+
+ Args:
+ title: 通知标题。
+ content: 已渲染的通知正文。
+
+ Raises:
+ ValueError: 微信协议配置不完整时抛出。
+ RuntimeError: 网关返回 HTTP 或业务错误时抛出。
+ """
+
</code_context>
<issue_to_address>
**小问题:** `send_openclaw_weixin` 的文档字符串承诺网关发生 HTTP 错误时会抛出 `RuntimeError`,但对于非 2xx 响应,`response.raise_for_status()` 会直接抛出 `httpx.HTTPStatusError`。依赖文档所述异常契约的调用方无法按照说明处理 HTTP 失败。
**触发条件:** 当 iLink 网关返回非 2xx HTTP 状态码时。
**建议修复:** 要么按照文档中所述的契约,将 `raise_for_status()` 统一包装为 `RuntimeError`;要么记录实际抛出的 `httpx.HTTPStatusError` 异常。
```suggestion
httpx.HTTPStatusError: 网关返回非 2xx HTTP 响应时抛出。
```
</issue_to_address>Sourcery 评估
需要人工审查。 需要先处理 1 个发现的问题;此外,启用后,此更改会将配置的机器人凭据和通知内容发送到外部 iLink 端点,并可能将消息发送给配置的微信用户。回滚可以阻止后续发送,但如果端点或请求行为有误,则无法撤回已发送的消息,也无法恢复已经传输的凭据或内容。
阻塞性发现:app/services/notification.py:309
Original comment in English
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="app/services/notification.py" line_range="308-309" />
<code_context>
+ "AuthorizationType": "ilink_bot_token",
+ "Authorization": f"Bearer {bot_token}",
+ "X-WECHAT-UIN": base64.b64encode(
+ str(secrets.randbits(32)).encode("ascii")
+ ).decode("ascii"),
+ "iLink-App-Id": "bot",
+ "iLink-App-ClientVersion": OPENCLAW_WEIXIN_CLIENT_VERSION,
</code_context>
<issue_to_address>
**issue (bug_risk):** The `X-WECHAT-UIN` header is base64-encoding the ASCII decimal representation of the random number, but the iLink protocol expects the base64 encoding of a 32-bit unsigned integer's binary bytes. The gateway rejects the header or cannot parse it, so every微信消息发送请求 fails protocol validation.
**Triggers:** When the iLink gateway validates the required `X-WECHAT-UIN` header.
**Suggested fix:** Encode the value with a fixed-width binary representation, such as `base64.b64encode(struct.pack(">I", secrets.randbits(32))).decode("ascii")`.
</issue_to_address>
### Comment 2
<location path="app/services/notification.py" line_range="268" />
<code_context>
else:
raise Exception(f"ServerChan 推送通知失败: {response.text}")
+ async def send_openclaw_weixin(self, title: str, content: str) -> None:
+ """通过微信公开的 OpenClaw/iLink HTTP 协议推送一条文本通知。
+
+ 这是通知渠道的最小单账号实现:账号登录与会话上下文由配置提供,
+ AUTO-MAS 不启动 OpenClaw 进程,也不负责二维码登录流程。
+
+ Args:
+ title: 通知标题。
+ content: 已渲染的通知正文。
+
+ Raises:
+ ValueError: 微信协议配置不完整时抛出。
+ RuntimeError: 网关返回 HTTP 或业务错误时抛出。
+ """
+
</code_context>
<issue_to_address>
**nitpick:** The `send_openclaw_weixin` docstring promises `RuntimeError` for gateway HTTP errors, but `response.raise_for_status()` raises `httpx.HTTPStatusError` directly for non-2xx responses. Callers relying on the documented exception contract cannot handle HTTP failures as specified.
**Triggers:** When the iLink gateway returns a non-2xx HTTP status.
**Suggested fix:** Either wrap `raise_for_status()` in `RuntimeError` consistently with the documented contract, or document the actual `httpx.HTTPStatusError` exception.
```suggestion
httpx.HTTPStatusError: 网关返回非 2xx HTTP 响应时抛出。
```
</issue_to_address>Sourcery assessment
Needs a human reviewer. 1 finding to address first, and when enabled, this change sends configured bot credentials and notification content to an external iLink endpoint and can deliver messages to the configured WeChat user. Reverting stops future sends but cannot retract messages or recover credentials or content already transmitted if the endpoint or request behavior is wrong.
Blocking findings: app/services/notification.py:309
| str(secrets.randbits(32)).encode("ascii") | ||
| ).decode("ascii"), |
There was a problem hiding this comment.
问题 (bug_risk): X-WECHAT-UIN 请求头正在对随机数的 ASCII 十进制表示进行 Base64 编码,但 iLink 协议要求对 32 位无符号整数的二进制字节进行 Base64 编码。网关会拒绝该请求头或无法解析它,因此每个微信消息发送请求都会无法通过协议验证。
触发条件: 当 iLink 网关验证必需的 X-WECHAT-UIN 请求头时。
建议修复: 使用固定宽度的二进制表示来编码该值,例如 base64.b64encode(struct.pack(">I", secrets.randbits(32))).decode("ascii")。
Original comment in English
issue (bug_risk): The X-WECHAT-UIN header is base64-encoding the ASCII decimal representation of the random number, but the iLink protocol expects the base64 encoding of a 32-bit unsigned integer's binary bytes. The gateway rejects the header or cannot parse it, so every微信消息发送请求 fails protocol validation.
Triggers: When the iLink gateway validates the required X-WECHAT-UIN header.
Suggested fix: Encode the value with a fixed-width binary representation, such as base64.b64encode(struct.pack(">I", secrets.randbits(32))).decode("ascii").
There was a problem hiding this comment.
您好——我发现了 1 个问题
面向 AI 代理的提示
请处理本次代码审查中的评论:
## 各项评论
### 评论 1
<location path="app/services/openclaw_qq.py" line_range="463-466" />
<code_context>
+ "OpenClawQQAppId": "",
+ "OpenClawQQTargetOpenId": "",
+ }
+ if self._can_persist_secrets():
+ values["OpenClawQQClientSecret"] = ""
+ async with self._config_lock:
+ await Config.update({"Notify": values})
+
+ async def send(self, title: str, content: str) -> None:
</code_context>
<issue_to_address>
**issue (bug_risk):** 当密钥存储不可用时,解绑操作会清除启用标志和非敏感字段,但会有意忽略加密凭据字段。如果之后安全存储恢复可用,旧令牌或客户端密钥仍会从配置中加载,导致即使用户已经解绑,通道仍会显示为已绑定。
**触发条件:** 当一个之前持久化的绑定在平台安全存储探测不可用期间被解绑,并且安全存储在下一次状态或通知操作之前恢复可用时。
**建议修复:** 只要配置层仍能更新加密凭据字段,就应在解绑过程中将其清除;或者记录一个持久化的墓碑标记,以防止重新使用过期的加密凭据。
</issue_to_address>Sourcery 评估
需要人工审查。 首先需要处理 1 个发现项;此外,此变更增加了基于二维码的账户绑定、凭据存储、后台会话轮询,以及向外部微信和 QQ 端点发送通知的功能。如果收件人或身份验证流程有误,消息或访问凭据可能会被发送到错误的外部账户,或继续留存在错误的外部账户中。回滚可以停止后续发送并移除本地行为,但无法撤回已经送达的通知,也无法撤销已在外部服务中建立的凭据和访问权限。
阻塞性发现:app/services/openclaw_qq.py:466
Original comment in English
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="app/services/openclaw_qq.py" line_range="463-466" />
<code_context>
+ "OpenClawQQAppId": "",
+ "OpenClawQQTargetOpenId": "",
+ }
+ if self._can_persist_secrets():
+ values["OpenClawQQClientSecret"] = ""
+ async with self._config_lock:
+ await Config.update({"Notify": values})
+
+ async def send(self, title: str, content: str) -> None:
</code_context>
<issue_to_address>
**issue (bug_risk):** When secret storage is unavailable, unbind clears the enable flag and non-secret fields but deliberately omits the encrypted credential fields. If secure storage becomes available again later, the old token or client secret is still loaded from configuration and the channel appears bound again despite the user having unbound it.
**Triggers:** When a previously persisted binding is unbound while the platform secure-storage probe is unavailable, then secure storage becomes available before the next status or notification operation.
**Suggested fix:** Clear encrypted credential fields as part of unbind whenever the configuration layer can still update them, or record a durable tombstone that prevents stale encrypted credentials from being reused.
</issue_to_address>Sourcery assessment
Needs a human reviewer. 1 finding to address first, and this adds QR-based account binding, credential storage, background session polling, and outbound notifications to external WeChat and QQ endpoints; if the recipient or authentication flow is wrong, messages or access credentials could reach or remain with the wrong external account. Reverting stops future sends and removes the local behavior, but it cannot unsend notifications already delivered or revoke credentials and access established with the external services.
Blocking findings: app/services/openclaw_qq.py:466
|
@sourcery-ai Review |
There was a problem hiding this comment.
您好——我已经审阅了您所做的更改,整体看起来很棒!
Sourcery 评估
需要人工审阅。 此更改增加了基于二维码的凭据获取与存储功能,以及向外部微信和 QQ 账户发送的出站消息,因此,错误的账户映射或凭据处理流程可能会暴露访问权限,或将通知发送给错误的收件人。回滚可以阻止后续请求,但无法撤回已经发送的消息,也不会自动删除已经持久化的凭据。
Original comment in English
Hey - I've reviewed your changes and they look great!
Sourcery assessment
Needs a human reviewer. This adds QR-based credential acquisition and storage plus outbound messages to external WeChat and QQ accounts, so a faulty account mapping or credential-handling path could expose access or send notifications to the wrong recipient. Reverting stops future requests but cannot recall messages already sent or automatically remove credentials already persisted.
|
if error_code in {-2, -14}:
await self._invalidate_binding(reason="微信登录状态已失效")官方 另外 Sourcery 那条 小问题:i18n 有 5 个键没有任何引用 —— 还想问一下 QQ 那边: |
|
已经跑通qq,send应该作为失效报错吧
…________________________________
From: qiyinxi ***@***.***>
Sent: Saturday, 05 September 2026 21:27:31
To: AUTO-MAS-Project/AUTO-MAS ***@***.***>
Cc: HarcoChen ***@***.***>; Author ***@***.***>
Subject: Re: [AUTO-MAS-Project/AUTO-MAS] feat(notify): 支持微信Claw (PR #560)
[https://avatars.githubusercontent.com/u/52456734?s=20&v=4]qiyinxi left a comment (AUTO-MAS-Project/AUTO-MAS#560)<#560 (comment)>
send() 里把 -2 和 -14 一起当成登录失效,一次推送撞上就会清掉 Bot Token 并关掉开关,用户得重新扫码:
if error_code in {-2, -14}:
await self._invalidate_binding(reason="微信登录状态已失效")
官方 Tencent/openclaw-weixin 只定义了 STALE_TOKEN_ERRCODE = -14(src/api/session-guard.ts:6),全仓没有对 -2 的处理;这个 PR 上一版对 -2 的注释也是「上下文过期」。现在 context_token 已经不发了,建议只保留 -14,-2 按普通失败报错。
另外 Sourcery 那条 X-WECHAT-UIN 是误报,官方 src/api/api.ts:221 的注释就是 random uint32 -> decimal string -> base64,和当前实现一致,不用按建议改成 struct.pack。
小问题:i18n 有 5 个键没有任何引用 ―― openclawWeixinTip、openclawQqTip、openclawWeixinBindSuccess、openclawQqBindSuccess、openclawWeixinUnbindFailed。
还想问一下 QQ 那边:/v2/users/{openid}/messages 不带 msg_id 走的是主动消息,官方有权限和频次配额,实际跑通过吗?
―
Reply to this email directly, view it on GitHub<#560?email_source=notifications&email_token=AJAENWUUHRZPAPK6RBL24KD5NQIEHA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKNJVGIYTGMJQGA42M4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2KYZTPN52GK4S7MNWGSY3L#issuecomment-5552131009>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AJAENWS47MUSKLAJMBLD4KL5NQIEHAVCNFSNUABFKJSXA33TNF2G64TZHM3TKMZWGA3TENBRHNEXG43VMU5TKMZVGU2DSOJUGQY2C5QC>.
You are receiving this because you authored the thread.Message ID: ***@***.***>
|
支持微信claw作为通知渠道,接入通知中心
Sourcery 摘要
通过通知中心支持可配置的微信(OpenClaw/iLink)通知。
新功能:
增强:
杂项:
Original summary in English
Sourcery 总结
通过二维码绑定和通知中心,启用 WeChat Claw/iLink 通知。
新功能:
增强功能:
测试:
维护工作:
Original summary in English
Sourcery 摘要
将基于二维码绑定的微信 Claw/iLink 和 QQ 官方机器人渠道集成到通知中心。
新功能:
错误修复:
增强功能:
文档:
测试:
杂项:
Original summary in English
Sourcery 摘要
将微信 Claw/iLink 和 QQ 官方机器人集成为通知中心中可通过二维码绑定的通知渠道。
新功能:
Bug 修复:
增强功能:
文档:
测试:
日常维护:
Original summary in English
Sourcery 总结
将基于二维码绑定的微信 Claw/iLink 和 QQ 官方机器人渠道集成到通知中心。
新功能:
错误修复:
增强功能:
文档:
测试:
杂项:
Original summary in English
Sourcery 摘要
将基于二维码绑定的微信 Claw/iLink 和 QQ 官方 Bot 渠道集成到通知中心,并提供安全的凭据管理和可靠的消息投递。
新功能:
错误修复:
增强功能:
文档:
测试:
维护:
Original summary in English
Sourcery 摘要
将微信 Claw/iLink 和 QQ 官方机器人集成为通知中心中支持二维码绑定的通知渠道。
新功能:
错误修复:
增强功能:
文档:
测试:
杂项:
Original summary in English
Sourcery 总结
将微信 Claw/iLink 和 QQ 官方机器人频道集成到通知中心,提供可靠的消息投递和安全的凭据管理。
新功能:
错误修复:
增强功能:
文档:
测试:
日常维护:
Original summary in English
Sourcery 摘要
将微信 Claw/iLink 和 QQ 官方机器人集成为支持二维码绑定的通知渠道,并实现安全的凭据处理和可靠的消息投递。
新功能:
Bug 修复:
增强功能:
文档:
测试:
维护工作:
Original summary in English
Sourcery 摘要
将微信 Claw/iLink 和 QQ 官方机器人集成为通知中心中安全管理、可通过二维码绑定的通知渠道。
新功能:
Bug 修复:
增强功能:
文档:
测试:
日常维护:
Original summary in English
Summary by Sourcery
Integrate WeChat Claw/iLink and QQ Official Bot as securely managed, QR-bindable notification channels in the notification center.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests:
Chores: