fix(wechat): wechat_push 工具漏挂企业微信 + 提取 active_channels 单一真相源 + bump 0.26.9
根因:wechat_push_available() 只看 clawbot_enabled(),没算企业微信。线上若只开 企微渠道(ClawBot 开关没开)→ 工具压根不注册到 agent → zcbot 照实回"没有直接 发企业微信的工具",用户已绑企微仍推不出。底层 send_to_user 早支持 push_wecom, 纯属注册门槛漏判。 修:提取 service.active_channels() 作渠道清单唯一真相源,门槛(wechat_push_available) 与投递(send_to_user)都引它,加渠道只改一处,根除"两处各列各的"这类偏差。 工具描述把 ~24h 窗口注明为 ClawBot-only(企业微信无窗口约束)。 纯内部重构,对外契约不变;test_secret_host_tools 8/8 过。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
23c5ab20e0
commit
8ab1805df4
|
|
@ -21,6 +21,12 @@
|
|||
|
||||
## 已完成关键能力
|
||||
|
||||
### 2026-06-25 / 修复 wechat_push 工具漏挂企业微信(只配企微也能推,bump 0.26.9)
|
||||
|
||||
- bug:`wechat_push_available()` 只返回 `service.clawbot_enabled()`,完全没算企业微信。线上若只开了企业微信渠道(ClawBot 开关没开)→ 工具压根没注册到 agent → zcbot 照实回"我没有直接发企业微信的工具"(用户已绑企微仍推不出)。底层 `send_to_user` 其实早支持 `push_wecom`,门槛漏判而已。
|
||||
- 修:提取 `service.active_channels()` 作渠道清单**唯一真相源** —— `wechat_push_available()` 改成 `bool(active_channels())`、`send_to_user()` 改成 `for ch in active_channels(): _DISPATCH[ch](...)`,门槛与投递同源,加渠道只改一处,根除"两处各列各的"这类漏判。工具描述把「~24h 窗口」注明为 ClawBot-only(企业微信无窗口约束),避免 agent 在企微场景误判窗口限制。纯内部重构,对外契约不变;`test_secret_host_tools` 8/8 过。
|
||||
- 文件:`tools/wechat_bot.py`、`core/wechat/service.py`。
|
||||
|
||||
### 2026-06-25 / 企业微信加「手填 userid」绑定(无域名也能推,bump 0.26.3)
|
||||
|
||||
- 痛点:企业微信只有 OAuth 扫码绑定那一路,而 OAuth 回调要落在 HTTPS 可信域名;用户暂无域名 → 卡住。关键认知:**企业微信推送是出站调用(gettoken/message_send 直连 qyapi),根本不需要域名**——只有"扫码拿 userid"那步要域名。
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
||||
# 改版本只动这一行。
|
||||
__version__ = "0.26.8"
|
||||
__version__ = "0.26.9"
|
||||
|
|
|
|||
|
|
@ -250,14 +250,27 @@ class DeliveryReport:
|
|||
return any(r.ok for r in self.results)
|
||||
|
||||
|
||||
def active_channels() -> list[str]:
|
||||
"""部署级「哪些渠道开了」的**唯一真相源**:门槛判断(`wechat_push_available`)
|
||||
与投递(`send_to_user`)都引它,避免两处各列各的(曾漏判企业微信致工具不挂)。
|
||||
加渠道只改这一处,门槛与投递自动一致。顺序即投递优先序。"""
|
||||
from core.wechat.wecom import wecom_configured
|
||||
chans: list[str] = []
|
||||
if clawbot_enabled():
|
||||
chans.append(_CLAWBOT)
|
||||
if wecom_configured():
|
||||
chans.append(_WECOM)
|
||||
return chans
|
||||
|
||||
|
||||
_DISPATCH = {_CLAWBOT: push_clawbot, _WECOM: push_wecom}
|
||||
|
||||
|
||||
def send_to_user(
|
||||
user_id: UUID, text: str = "", file_path: Optional[str] = None
|
||||
) -> DeliveryReport:
|
||||
"""渠道抽象:按用户已绑渠道投递。当前仅 ClawBot;企业微信(渠道 B)后续追加。"""
|
||||
"""渠道抽象:按 `active_channels()` 列出的已开渠道依次投递。"""
|
||||
report = DeliveryReport()
|
||||
if clawbot_enabled():
|
||||
report.results.append(push_clawbot(user_id, text, file_path))
|
||||
from core.wechat.wecom import wecom_configured
|
||||
if wecom_configured():
|
||||
report.results.append(push_wecom(user_id, text, file_path))
|
||||
for ch in active_channels():
|
||||
report.results.append(_DISPATCH[ch](user_id, text, file_path))
|
||||
return report
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@ from .base import FileOutOfBounds, Tool
|
|||
|
||||
|
||||
def wechat_push_available() -> bool:
|
||||
"""任一微信渠道可用(当前 = ClawBot 开关在;后续 or 企业微信配齐)。"""
|
||||
return service.clawbot_enabled()
|
||||
"""任一微信渠道开着就挂工具(ClawBot 个人微信 / 企业微信)。渠道清单的唯一真相源
|
||||
是 `service.active_channels()`,与 `send_to_user` 的投递口径同源,不再各列各的。"""
|
||||
return bool(service.active_channels())
|
||||
|
||||
|
||||
_REASON_HINT = {
|
||||
|
|
@ -33,10 +34,11 @@ class WechatPushTool(Tool):
|
|||
name = "wechat_push"
|
||||
description = (
|
||||
"Proactively push a short text message (and optionally one result file, e.g. a .docx/.pdf "
|
||||
"report) to the user's bound WeChat. Use when the user asks to send something to their "
|
||||
"WeChat, or when a scheduled task should deliver its output there. NOTE: WeChat push only "
|
||||
"works if the user has messaged the bot within the last ~24h; if it returns a window/binding "
|
||||
"error, fall back to send_email. The file path is relative to the working directory."
|
||||
"report) to the user's bound WeChat (personal WeChat via ClawBot, or WeCom/企业微信). Use "
|
||||
"when the user asks to send something to their WeChat, or when a scheduled task should "
|
||||
"deliver its output there. NOTE: the ~24h-window constraint applies ONLY to the personal "
|
||||
"WeChat (ClawBot) channel — WeCom (企业微信) has no window limit. If it returns a "
|
||||
"window/binding error, fall back to send_email. The file path is relative to the working directory."
|
||||
)
|
||||
parameters = {
|
||||
"type": "object",
|
||||
|
|
|
|||
Loading…
Reference in New Issue