全面升级:WeChat 3.9.5.81 + 全尺寸图片 OCR + 启动脚本
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 2.8 MiB |
@@ -0,0 +1,153 @@
|
||||
# 老莫微信消息 → serve session 路由设计方案
|
||||
|
||||
> 2026-05-20
|
||||
> 目标:老莫给机器人号发微信,小小莫也能看到,不依赖莫荷转述
|
||||
|
||||
---
|
||||
|
||||
## 现状
|
||||
|
||||
```
|
||||
你微信 → wxhelper TCP (:19099) → wechat_agent.py
|
||||
↓
|
||||
Hermes API (:8642)
|
||||
↓
|
||||
莫荷回复你
|
||||
```
|
||||
|
||||
莫荷独占所有微信消息。小小莫只能被动等她转述。
|
||||
|
||||
---
|
||||
|
||||
## 目标
|
||||
|
||||
```
|
||||
你微信 → wxhelper TCP → wechat_agent.py ─┬→ Hermes API → 莫荷 (不变)
|
||||
└→ opencode serve (:4096) → 小小莫看到
|
||||
```
|
||||
|
||||
新增一条岔路:老莫的消息同时写入 serve session,小小莫可主动查看。
|
||||
|
||||
---
|
||||
|
||||
## 方案对比
|
||||
|
||||
### 方案 A:subprocess 调用 `opencode run --attach --message`
|
||||
|
||||
**做法**:wechat_agent.py 的 `process_msg()` 里加一段:
|
||||
|
||||
```python
|
||||
def fork_to_session(fu, ct):
|
||||
"""将消息写入 opencode serve session (非阻塞)"""
|
||||
if fu != "wxid_c0a6izmwd78y22":
|
||||
return # 只转发老莫
|
||||
try:
|
||||
import subprocess
|
||||
subprocess.run(
|
||||
["opencode", "run", "--attach", "http://localhost:4096",
|
||||
"--password", "hermes123",
|
||||
"--session", SESSION_ID,
|
||||
"--message", f"[老莫] {ct}"],
|
||||
capture_output=True, timeout=10,
|
||||
env={**os.environ, "PYTHONHOME": ""}
|
||||
)
|
||||
except Exception as e:
|
||||
log(f"FORK ERR (non-fatal): {e}")
|
||||
```
|
||||
|
||||
| 方面 | 评估 |
|
||||
|------|------|
|
||||
| 复杂度 | ⭐ 低,~10 行代码 |
|
||||
| 对现有链路影响 | ❌ **无**,fork 是独立线程,失败不影响 Hermes |
|
||||
| session ID 稳定性 | ⚠️ serve 重启后 ses_xxx 会变 → 需想办法拿到当前 ID |
|
||||
| 性能开销 | subprocess 每次约 1-2 秒,但独立线程不阻塞主流程 |
|
||||
| serve 密码硬编码 | ⚠️ 已经在代码库(hermes123),无新增风险 |
|
||||
| 可靠性 | subprocess 可能因 PATH/PYTHONHOME 问题失败 |
|
||||
|
||||
### 方案 B:直接 HTTP POST 调用 serve API
|
||||
|
||||
**做法**:抓包分析 `opencode run --attach` 的 HTTP 协议,直接用 `urllib.request` POST:
|
||||
|
||||
```python
|
||||
# 伪代码,serve API 协议未知,需逆向
|
||||
urllib.request.urlopen("http://localhost:4096/api/session/inject",
|
||||
data=json.dumps({"session": SID, "message": "[老莫] xxx"}))
|
||||
```
|
||||
|
||||
| 方面 | 评估 |
|
||||
|------|------|
|
||||
| 复杂度 | ⭐⭐⭐ 未知,需逆向 serve API |
|
||||
| 性能 | ✅ 纯 HTTP,无 subprocess 开销 |
|
||||
| 稳定性 | ⚠️ 非官方 API,版本更新可能不兼容 |
|
||||
|
||||
### 方案 C:写 inbox 文件 + 小小莫轮询
|
||||
|
||||
**做法**:wechat_agent 写文件,小小莫定期读取
|
||||
|
||||
| 方面 | 评估 |
|
||||
|------|------|
|
||||
| 复杂度 | ⭐ 最低 |
|
||||
| 即时性 | ❌ 需要轮询,无法实时 |
|
||||
|
||||
---
|
||||
|
||||
## 关键风险
|
||||
|
||||
### 1. session ID 稳定性(最核心)
|
||||
|
||||
`opencode run --attach` 需要 session ID。每次 serve 重启后,当前 TUI session 的 ID 可能变化:
|
||||
- 如果 serve 重启 → 老 session 消失 → 新 session 新 ID → 需要更新 wechat_agent 里的配置
|
||||
- **解决思路**:用 session 名称而不是 ID,或每次启动时自动获取
|
||||
|
||||
### 2. 不对莫荷通信造成任何影响
|
||||
|
||||
**铁律**:fork 到 session 的代码必须:
|
||||
- 在独立线程中运行
|
||||
- 捕获所有异常
|
||||
- 设置超时(≤10 秒)
|
||||
- 永远不阻塞 `call_hermes()` 和 `send_wx()`
|
||||
|
||||
### 3. 循环消息风暴
|
||||
|
||||
如果我不小心回了一条 `[老莫]` 到 session,wechat_agent 不能把它再 fork 一次。
|
||||
- 现有的 `is_self` 检查已经过滤自己发送的消息
|
||||
- 但如果 serve session 的消息被 serve 再推给 wechat_agent... 需要确认不会发生
|
||||
|
||||
### 4. `opencode` CLI 在 wechat_agent 环境中是否可用
|
||||
|
||||
wechat_agent 以 `$env:PYTHONHOME=''` 启动,`opencode.cmd` 可能也依赖 Python。
|
||||
- 需测试:从 Python subprocess 能否直接调用 `opencode run --attach --message`
|
||||
|
||||
---
|
||||
|
||||
## 推荐方案
|
||||
|
||||
**方案 A**(subprocess)最稳妥:
|
||||
1. 对现有链路零影响
|
||||
2. 改动最小
|
||||
3. 可以逐步优化(先 subprocess,后改 HTTP API)
|
||||
|
||||
### 待确认事项
|
||||
|
||||
1. **serve session ID 如何维护?**
|
||||
- 能否用固定名称?还是每次启动获取?
|
||||
- 如果 serve 重启导致 ID 变了,wechat_agent 如何感知?
|
||||
|
||||
2. **`opencode run --attach --message` 是否支持在 Python subprocess 中调用?**
|
||||
- 需要验证 CLI 安装路径和调用方式
|
||||
|
||||
3. **是否需要前缀路由?**
|
||||
- 是全部消息都 fork?
|
||||
- 还是只有特定前缀(如 `[小小莫]` 开头的消息)才 fork?
|
||||
|
||||
---
|
||||
|
||||
## 验证清单
|
||||
|
||||
实现后验证:
|
||||
- [ ] 老莫发微信 → 莫荷正常回复(链路不变)
|
||||
- [ ] 老莫发微信 → serve session 能看到消息(新增)
|
||||
- [ ] `opencode run --attach` 超时/失败 → 莫荷通信不受影响
|
||||
- [ ] 老莫连续发多条 → 都能看到
|
||||
- [ ] wechat_agent 重启后依然工作
|
||||
- [ ] serve 重启后 session ID 变化时能自动适配
|
||||
@@ -0,0 +1,184 @@
|
||||
# 通用架构:WeChat ↔ opencode 双向桥接
|
||||
|
||||
> 2026-05-20
|
||||
> 剥离 Hermes AI 依赖,建立 opencode serve 与微信账号之间的通用双向通道
|
||||
|
||||
---
|
||||
|
||||
## 核心理念
|
||||
|
||||
微信机器人本质是一套通用的消息路由系统:
|
||||
|
||||
```
|
||||
微信 ←→ wxhelper ←→ 桥接代理 ←→ 任何 AI / 程序
|
||||
```
|
||||
|
||||
**不应该是"莫荷专属"**。当前架构把 Hermes API 硬编码在桥接逻辑中,限制了通用性。
|
||||
|
||||
---
|
||||
|
||||
## 架构对比
|
||||
|
||||
### 当前(莫荷专用,双机)
|
||||
|
||||
```
|
||||
你微信 → wxhelper TCP → wechat_agent → Hermes API (:8642, Linux) → 莫荷回复
|
||||
↑
|
||||
消息路由硬编码,改一处都要动 agent
|
||||
```
|
||||
|
||||
### 目标(通用,纯 Windows)
|
||||
|
||||
```
|
||||
你微信 → wxhelper TCP → Bridge Agent ─┬→ opencode serve session (小小莫看到)
|
||||
│
|
||||
└→ HTTP API (:5801) 供任何程序消费
|
||||
↑
|
||||
serve 里的 AI / 外部程序 POST 回复
|
||||
```
|
||||
|
||||
**关键变化**:桥接代理不再"替 AI 做决定",而是变成**中立的消息通道**:
|
||||
|
||||
| 功能 | 现状 (wechat_agent.py) | 目标 (Bridge Agent) |
|
||||
|------|----------------------|-------------------|
|
||||
| 收到微信消息 | 直接 POST Hermes API | **写入 serve session + 提供 HTTP 消费接口** |
|
||||
| 消息路由 | 硬编码 (call_hermes) | 无业务逻辑,只负责转发 |
|
||||
| AI 是谁 | 只能是莫荷 (Hermes) | 可以是 serve 里的任何人(Sisyphus、莫荷...) |
|
||||
| 外部调用 | :5801 简陋收消息 | http API 收消息 |
|
||||
|
||||
---
|
||||
|
||||
## 通用架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Windows 192.168.0.111 │
|
||||
│ │
|
||||
│ ┌──────────────────────┐ │
|
||||
│ │ 微信 3.9.10.19 机器人 │ │
|
||||
│ │ (wxid_xxxxxxxxx) │ │
|
||||
│ └────────┬─────────────┘ │
|
||||
│ │ wxhelper TCP (:19099) → 收消息 │
|
||||
│ │ wxhelper HTTP (:19088) → 发消息 │
|
||||
│ ▼ │
|
||||
│ ┌────────────────────────────────────────────┐ │
|
||||
│ │ Bridge Agent (bridge.py v3) │ │
|
||||
│ │ │ │
|
||||
│ │ ┌────────────────────────────────────┐ │ │
|
||||
│ │ │ 消息收 (TCP thread) │ │ │
|
||||
│ │ │ 收到微信消息 → 写入 serve session │ │ opencode │
|
||||
│ │ │ → 触发 webhook(可选) │──┼──→ serve :4096 │
|
||||
│ │ └────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ ┌────────────────────────────────────┐ │ │
|
||||
│ │ │ HTTP API 服务 (:5801) │ │ │
|
||||
│ │ │ POST /send → 发微信 │ │ │
|
||||
│ │ │ POST /history → 查历史 │ │ │
|
||||
│ │ │ POST /inject → 写 serve 会话 │ │ │
|
||||
│ │ └────────────────────────────────────┘ │ │
|
||||
│ └────────────────────────────────────────────┘ │
|
||||
│ │ ▲ │
|
||||
│ │ serve session 里的 AI │ HTTP POST /send │
|
||||
│ ▼ │ │
|
||||
│ ┌────────────────────────────────────┐ │ │
|
||||
│ │ opencode serve TUI │ │ │
|
||||
│ │ (Sisyphus / 任何 Agent) │──┘ │
|
||||
│ │ │ │
|
||||
│ │ 「老莫:今天吃了吗」← 从 session 看到 │ │
|
||||
│ │ 「回复:[xxm] 吃了」→ POST :5801 │ │
|
||||
│ └────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 数据流
|
||||
|
||||
### 微信消息 → AI(上行)
|
||||
|
||||
```
|
||||
1. 老莫发微信给机器人号
|
||||
2. wxhelper DLL 通过 TCP (:19099) 推送给 Bridge Agent
|
||||
3. Bridge Agent 收到消息,写入 serve session:
|
||||
subprocess.run(["opencode", "run", "--attach",
|
||||
"--message", "[老莫] 消息内容"])
|
||||
4. 同时,消息可通过 :5801 HTTP API 被任何订阅者消费
|
||||
5. serve session 里的 AI 在 TUI 或通过 session_search 看到
|
||||
```
|
||||
|
||||
### AI 回复 → 微信(下行)
|
||||
|
||||
```
|
||||
1. AI 决定回复 → POST http://localhost:5801/send
|
||||
{"to": "wxid_xxx", "message": "回复内容"}
|
||||
2. Bridge Agent 收到 → wxpost /api/sendTextMsg
|
||||
3. wxhelper DLL 发送 → 老莫手机收到
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bridge Agent 接口规范
|
||||
|
||||
### HTTP API (:5801)
|
||||
|
||||
| 方法 | 路径 | 用途 | Body |
|
||||
|------|------|------|------|
|
||||
| POST | `/send` | 发微信消息 | `{"to":"wxid","message":"text"}` |
|
||||
| POST | `/history` | 查聊天记录 | `{"wxid":"...","count":20}` |
|
||||
| POST | `/recent` | 最近联系人 | 无 |
|
||||
| POST | `/inject` | 写 serve session | `{"message":"[xxm] 内容"}` |
|
||||
| GET | `/health` | 健康检查 | 无 |
|
||||
|
||||
### 输出到 serve session 的格式
|
||||
|
||||
```
|
||||
[老莫] 消息内容 → 来自微信的普通消息
|
||||
[老莫|昵称] 消息内容 → 带昵称
|
||||
[系统] 新联系人 xxx → 系统事件
|
||||
[session:<id>] 启动签到 → Agent 上线通知
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 与 Hermes AI 的关系
|
||||
|
||||
Hermes 不再是架构的核心组件,而是可选的消息消费者之一:
|
||||
|
||||
```
|
||||
┌─→ opencode serve session → Sisyphus (小小莫)
|
||||
老莫微信 → Bridge ──┤
|
||||
└─→ 消费 HTTP API 的任意程序
|
||||
│
|
||||
┌─────┴─────┐
|
||||
│ │
|
||||
Hermes AI 其他 AI
|
||||
(莫荷) (未来)
|
||||
```
|
||||
|
||||
**迁就策略**:
|
||||
1. 第一阶段:Bridge Agent 同时写 serve session + POST Hermes API(现状保留)
|
||||
2. 第二阶段:Bridge Agent 只写 serve session,Hermes 通过 serve session 接入
|
||||
3. 第三阶段:完全通用化,Hermes 只是 serve session 里的一个 AI 角色
|
||||
|
||||
---
|
||||
|
||||
## 实施原则
|
||||
|
||||
1. **不破坏现有链路** — Bridge Agent 改造期间,Hermes 消息路由不变
|
||||
2. **增量迁移** — 先加新功能,再逐步替换旧逻辑
|
||||
3. **session 为主** — 所有消息以 serve session 为中心,HTTP API 为辅助
|
||||
4. **最低依赖** — 纯 Windows 可运行,不需要 Linux 端 Hermes
|
||||
|
||||
---
|
||||
|
||||
## 开放问题
|
||||
|
||||
1. **session ID 管理**:Bridge Agent 如何知道当前有效的 session ID?
|
||||
2. **session write 方式**:subprocess (`opencode run --attach --message`) 是否有更轻量的替代?
|
||||
3. **消息去重**:写 session + POST Hermes 可能导致重复处理?
|
||||
4. **serve 重启恢复**:Bridge Agent 如何在 serve 重启后自动重连?
|
||||
5. **历史消息**:AI 上线后能否拉取 session 中已有的消息历史?
|
||||
|
||||
---
|
||||
|
||||
*参考:projects/wechat-hermes-gateway/docs/老莫消息路由设计.md*
|
||||
Reference in New Issue
Block a user