Files
dsh_ai1net_server/交付物/唤醒的解决方式-官方文档核对与方案分析-20260930.md
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次)
- .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…),
  目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪
- .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/)
- .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*)
- .gitignore 补:备份件(*.bak-*)
- 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

239 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 「唤醒」的解决方式 · 官方文档核对 + 方案分析(2026-09-30)
> 用户议题:**处理完成后分析唤醒的解决方式,再看看官方文档;如果找不到办法,是不是可以用一个会话当主会话、用手机给当前会话发消息的方式唤醒。**
> 用户补充(关键):**「之前手机记得是通过 gateway 连接的」** —— 对,手机走的是**我们自研的那条 gateway 通道**,不是官方微信助理。
---
## 0 三句话结论
1. **官方文档里没有"分钟级定时"这回事** —— 官方唯一的时间驱动是**自动化**,本机实测出现的 recurrence 只到 `FREQ=HOURLY;INTERVAL=1`(**每小时**为最小)。
2. **但官方把"手机发消息 → 电脑执行"做成了产品**(微信助理 / 企微助理),而且它的形态写得很直白:
**「助理(远程任务):仅一个会话,所有远程指令集中处理」** ⇒ **正是你说的"用一个会话当主会话"**。
3. **你的思路成立,而且不用新造轮子** —— 我们自研的 gateway 通道**本来就具备"往会话投一条消息"的能力且已验收**(手机接入线 V2)。**唯一的硬前提是:那个会话必须是桌面"当前打开的那一个"(live)**;不是 live ⇒ `reply` 一律 `409`。
⚠️ **后续追加(13:0x)**:用户提出"回到自动任务,建**间隔 5 分钟**自动运行的会话" ⇒ **§11 给出源码级判定:做不到**(FREQ 硬白名单),且一次运行=一个新会话 ⇒ 附能做的三档。
---
## 1 官方文档核对(逐条附原文)
| 项 | 官方怎么说 | 出处 |
|---|---|---|
| 自动化的定位 | 「自动化在**本地客户端**保存定时任务配置…在指定时间**以您当前的登录身份自动发起 Agent 任务**」 | `.../Function-Description/Automation-Guide` |
| 频率粒度 | 只举「**每周一、三、五 09:00**」「**每月 1 日、15 日、28 日 09:00**」;**通篇未承诺分钟级** | 同上 |
| 谁在跑 | 「任务**仅在配置的时间规则触发时**执行,受任务频率、最大执行时长与系统并发控制限制」 ⇒ **是"时间规则",不是"事件/条件"** | 同上 |
| 需要电脑开着 | 同页未直说;**非官方**来源明确:「本机执行…需要保持电脑开机、WorkBuddy 客户端处于运行状态」 | 第三方(标记:**非官方**) |
| **手机通道(有)** | 「接入微信助理让您可以通过**手机微信远程控制电脑上的 WorkBuddy**。在微信中发送任务指令,WorkBuddy 在电脑上自动执行,并将结果同步回微信聊天窗口」 | `WeixinBot-Guide` |
| **助理 = 单会话** | 「**助理(远程任务):仅一个会话,所有远程指令集中处理**」;「工作目录:**固定使用助理专属文件夹**」;「上下文:**保留完整对话历史,不可清空**」 | `Wecom-Guide` §远程任务与普通任务的区别 |
| 企微可 @机器人 | 「在**群聊中 @机器人**下发团队协作任务」;「创建**专属任务群**,长期绑定」;含「任务提醒/发布通知」 | `Wecom-Guide` |
| 官方推荐形态 | 「**专属常开主机**:如果您的项目需要长期运行的任务(如定时巡检、持续集成监控等),可以使用一台专用的…电脑,保持 WorkBuddy 持续运行」 | `WeixinBot-Guide` |
| 版本门槛 | 需 **WorkBuddy ≥ 4.6.4** ⇒ **本机实测 5.6.2 ✅**(能力在,只是没启用) | 两份 Guide |
| 「条件触发」 | ⚠️ **只有非官方来源**提「条件触发(有新邮件/文件更新/关键词出现)」;**官方 Automation-Guide 只写"时间规则"** ⇒ **当作未证实,不作为设计依据** | 非官方 |
> 📌 **一句话**:官方给的两条"人能远程驱动电脑"的路,一条是**定时(最小 1 小时)**,一条是**手机发消息(人驱动,粒度任意)**。**官方没有第三条**。
---
## 2 两条手机通道别混(你记得对:我们用的是 gateway 那条)
| | **官方**(微信/企微助理) | **我们的**(自研覆盖网络 + 垫片 + gateway) |
|---|---|---|
| 手机 → 电脑 | 微信/企微 → 官方助理服务(长连接) | ai1net 覆盖网络 **443** → 本机垫片 `127.0.0.1:20090` → **WorkBuddy gateway(动态口)** |
| 能投到哪些会话 | **只能进"助理"那一个会话** | **可投到任意"同工作目录且 live"的会话** ✅ 更通用 |
| 是否单会话 | 是(助理天生单会话) | 不限定(但 `reply` 只认 live) |
| 依赖 | 微信/企微账号绑定、电脑常开 | 覆盖网络 + 垫片常驻 + 账号核对 |
| 本机现状 | **未启用**(库里 **0 条**远程来源会话;但客户端里有 `settings.claw.*` 字样 ⇒ 能力在) | ✅ **已通**(见 §3) |
会话侧契约(`交付物/手机App经覆盖网络操作WorkBuddy-架构定稿v3-20260929.md` §2.2,**已实测**):
```
⑤ 发消息
· 目标 = live 会话 ⇒ POST /api/v1/sessions/{id}/reply {"text":"…"} ← 官方路径,不夺 writer
(缺 text ⇒ 400;**非 live ⇒ 409**)
· 目标 ≠ live ⇒ 只能走 ACP 借用(session/load + session/prompt)
⚠️ 被 writer 占用 ⇒ -32000 writer_occupied ⇒ **夺不了,也不许抢**(T2/红线)
④ 哪个是 live ⇒ GET /api/v1/sessions/live → {sessionId, writerOccupied}
🔴 网关只读写"与自己同 cwd"的会话(跨项目一律 404)
```
---
## 3 本机实测读数(**只读**,口令未回显、未落盘)
| 查什么 | 读数 |
|---|---|
| 环境里的网关口令 | **在**(长度 43) |
| 垫片 `127.0.0.1:20090` | **在听**(PID 39220) |
| 网关口 `56975` | **活着**;`GET /api/v1/info` ⇒ `cwd = E:\ProgramData\AIProject\ai1net-dsh-server`(正是本工作区)✅ |
| **当前活会话** `GET /sessions/live` | 🔴 **`fe146dd9-…`,且 `writerOccupied: true`** |
| 看板认定的"主会话" | `6ecf6d98`(=我当前所在的这个接续会话) |
| 自动化台账 | ACTIVE:`once` **59 条** / `recurring` 2 条;PAUSED recurring 1 条 |
| 本机出现过的 recurrence | `FREQ=HOURLY;INTERVAL=1`(**最小=每小时**)、`FREQ=DAILY;BYHOUR=6`、`FREQ=DAILY;INTERVAL=3;BYHOUR=9` |
| 有没有分钟级 | `MINUTELY`/`SECONDLY` 命中 **0** ⇒ 本机从未有过分钟级 |
### 3.1 🔴 最关键的一条:**"主会话"现在不是 live**
`reply` 只认 live,而**当前 live 是 `fe146dd9`,不是主会话 `6ecf6d98`**。
⇒ **现在用手机发消息,只会进 `fe146dd9`,进不了主会话。** 这不是权限问题,是这个 API 的设计(不夺 writer 的代价就是"只认当前打开的那个")。
---
## 4 你的方案判定:**可行** —— 但成立与否只取决于一个前提
> 你的原话:**「用一个会话当主会话,用手机给当前会话发消息的方式唤醒」**
**判定:✅ 技术通路已存在、已验收,不需要新造。** 拆开看:
| 你的构想 | 对应现实 | 判定 |
|---|---|---|
| 「用一个会话当主会话」 | 机制里已有"主会话"概念(`collabd` / 看板同一套判据),也有 `wake.sessionId` 登记 | ✅ 现成 |
| 「用手机发消息」 | 自研通道已验收 V2:**手机发出的消息进入桌面会话** | ✅ 现成 |
| 「唤醒」 | 一条消息落进会话 ⇒ 会话被驱动起一轮 ⇒ **这就是唤醒** | ✅ 语义成立 |
| 「给**当前**会话发」 | `POST /sessions/{id}/reply`,**不夺 writer**;但**必须是 live** | ⚠️ **唯一硬前提** |
**⇒ 落地要点:让"主会话"="桌面上一直开着的那一个"。**
只要你**固定同一个会话、并在桌面一直开着它**,它就恒为 live,手机消息就恒能进去 —— 这就是你说的方案的最小实现,**零新增组件**。
---
## 5 三条路(粒度 / 是否需要人 / 现状 / 风险)
| # | 路 | 粒度 | 要人在场 | 现状 | 主要风险 |
|---|---|---|---|---|---|
| **A** | **人用手机发一条消息**(走自研 443 通道,或官方微信助理) | **任意** | 要 | ✅ 立即可用 | 必须目标会话 live,否则 409(⛔ 不许抢 writer) |
| **B** | **外部定时器**(手机快捷指令 / 服务器 cron 47.77.182.89)→ 走**同一条 443 通道** → `reply` | **可到分钟级** | 不要 | 🔧 通道已通,缺"定时那一端" | 需账号凭据载体;须守 V7 七条(限流/超时/不夺会话);静默失败要有告警 |
| **C** | 启用**官方微信/企微助理**,把主会话搬到"助理"那个唯一会话 | 人驱动=任意;自动仍受 1 小时限 | 看谁发 | ⚠️ **未启用**(版本够) | 助理**工作目录固定**(不是本项目)⇒ 我们的机制按 cwd 判归属会**不认它**;跨设备/群聊语义也不同 |
### 🔴 为什么"5 分钟级自动唤醒"只能走 B
| 通道 | 能不能到分钟级 | 为什么 |
|---|---|---|
| 网关 `scheduled-tasks` | ❌ | 桌面端硬编码 `CODEBUDDY_DISABLE_CRON=1`,调度器**从不启动**(已定案) |
| WorkBuddy 自动化 | ❌ | 实测最小 `FREQ=HOURLY;INTERVAL=1` = **1 小时**;官方文档也只举周/月 |
| 钩子 | ❌ | 事件驱动;**没人动 = 没事件** |
| 常驻进程(本机) | ❌ | 不是 WorkBuddy 后代 ⇒ **读不到网关口令** |
| **外部定时器 → 443 通道** | ✅ | 定时器在**外面**(不受 WorkBuddy 限制),投递走**已建好的通道** |
---
## 6 四个必须同时满足的前提(缺一即失败)
| # | 前提 | 现状 | 不满足会怎样 |
|---|---|---|---|
| 1 | 目标会话 **= 桌面当前打开的那个**(live) | 🔴 **当前不满足**(live 是 `fe146dd9`) | `reply` ⇒ **409**;若改走 ACP 借用 ⇒ 目标被 writer 占用时**夺不了**,且 **T2 明令不许抢** |
| 2 | 该会话的 **cwd = 网关 cwd** | ✅ 已是本工作区 | 网关跨 cwd 一律 **404 SESSION_NOT_FOUND** |
| 3 | 电脑常开 + WorkBuddy 运行 + 垫片/覆盖网络在 | ✅ 20090 在听、网关活着 | 通道整条断(官方也这么要求) |
| 4 | 守 **V7 七条**(单向依赖/不夺会话/限流/超时熔断/不占资源…) | ✅ 已定稿 | 违反即事故:**绝不允许"手机侧的问题"变成"WorkBuddy 异常"** |
---
## 7 建议(已定项,不是征询)
1. **主会话 = 一个固定会话 + 桌面一直开着它**。这是你方案的最小实现,**先按这个用**(人发即唤醒,零新增组件)。
2. **机制侧补一条"一致性校验",不改选择逻辑**:在收尾自判/看板里增加一项 —— 用 `GET /api/v1/sessions/live` 核「主会话是否就是 live」,**不一致就在看板上标黄**(而不是偷偷投不到)。理由:`reply` 的客观判据就是 live,现在机制里的"主会话"是**按标题/工作区猜**的,两者会漂移(今天实测就差了一个)。
3. **要不要"自动"由你定**:
- 选**接受人发** ⇒ 到此为止,最省、最符合"别老用自动任务"。
- 选**要自动(分钟级)** ⇒ 只能走 **B**:在**手机侧或服务器**放定时器,走 443 通道 `reply`;⚠️ 这条要单独评审(凭据载体 + 限流 + 静默失败告警),**不建议今天顺手做**。
4. ⛔ **不建议**为了"能投到任意会话"去动 `reply` 的语义或抢 `writer_occupied` —— 那是 `v3 §0.5 T2` 与红线明文禁止的。
---
## 8 图:唤醒消息的实际路径(这条链比"定时"更可靠)
```
[你/定时器] [外面] [本机] [桌面]
手机 App ──┐
├─→ ai1net 覆盖网络 ──→ 垫片 20090 ──→ WorkBuddy gateway ──→ 会话
服务器 cron ┘ (HTTPS 443) (注入 x-access-token) (动态口 56975) ↑
(剥掉 Origin) │
必须是 live ⚠️
失败方向:关掉自己(503/409)→ ⛔ 绝不影响 WorkBuddy
```
---
## 9 顺带发现(⚠️ 未处理,仅报告)
| # | 发现 | 影响 |
|---|---|---|
| 1 | 库里 **59 条 `once` 自动化仍是 ACTIVE**(早已跑完) | 统计虚高(旧坑 P7);⛔ 我没动(不擅自清) |
| 2 | 本机**未启用**官方微信/企微助理(0 条远程来源会话) | 备选路 C 处于"可开未开"状态 |
| 3 | 客户端源码里有 `settings.claw.*` 系列文案 ⇒ 助理能力确实在,只是没绑定 | 与版本 5.6.2 ≥ 4.6.4 一致 |
---
## 10 出处
| 内容 | 位置 |
|---|---|
| 官方 · 自动化 | `https://www.workbuddy.cn/docs/workbuddy/From-Beginner-to-Expert-Guide/Function-Description/Automation-Guide` |
| 官方 · 微信助理 | `https://www.workbuddy.cn/docs/workbuddy/WeixinBot-Guide` |
| 官方 · 企微助理(**含"助理=单会话"对比表**) | `https://www.workbuddy.cn/docs/workbuddy/Wecom-Guide` |
| 本项目 · 会话侧契约(实测) | `交付物/手机App经覆盖网络操作WorkBuddy-架构定稿v3-20260929.md` §2.2 / §0.5 |
| 本项目 · 唤醒为何从未响(定案) | `交付物/查唤醒为什么断-结论-20260930.md` |
| 非官方(已标注未证实) | `ima.qq.com` 知识库里的 WorkBuddy 教程文("条件触发"来源) |
---
## 11 追加判定(13:0x):「间隔 **5 分钟**自动运行的会话」——**产品层面做不到**
> 用户提议:**「一个会话不能多个主会话同时执行,所以还是只能回到自动任务,考虑在主会话工作区下创建间隔 5 分钟自动运行的会话」**
> 判定:**5 分钟这个粒度不存在**,且"自动化会话"与"唤醒主会话"是两件事。下面是证据。
### 11.1 源码级证据:`FREQ` 是**硬白名单**
客户端自带的 rrule 解析器(`app.asar` → `/main/log-acl-guard.js`,偏移 ≈403.6 KB 起)原文:
```js
const rawFreq = map.get("FREQ");
if (!rawFreq) invalidRule("missing FREQ");
if (rawFreq !== "HOURLY" && rawFreq !== "DAILY" && rawFreq !== "WEEKLY"
&& rawFreq !== "MONTHLY" && rawFreq !== "YEARLY")
invalidRule(`unsupported FREQ=${rawFreq}`);
...
interval: parsePositiveInt(map.get("INTERVAL"), 1) // INTERVAL ≥ 1,单位由 FREQ 决定
```
| 事实 | 读数 |
|---|---|
| 全包检索 `MINUTELY` / `SECONDLY` | **命中 0 处** |
| `INTERVAL` 下限 | `parsePositiveInt(..., 1)` ⇒ **≥1**,单位=FREQ ⇒ `HOURLY;INTERVAL=1` = **每小时 = 理论最小** |
| 是否只是 UI 限制 | ❌ **不是**。源码注释明写:同一实现**在 workbuddy-server `automation/schedule-utils.ts` 与 VSCode 扩展 `automation-storage.ts` 各有一份等价副本,多处必须同步改** ⇒ **三层一致** |
| `HOURLY` 能否错开分钟 | ⚠️ `formatRRule` 对 HOURLY 只输出 `FREQ=HOURLY;INTERVAL=n;BYDAY=…`,**不产出 BYMINUTE** ⇒ HOURLY 一律落在**整点那一分钟** |
⇒ **无法创建"间隔 5 分钟"的自动任务。**
🔴 若绕过 UI 手改 DB 塞 `FREQ=MINUTELY` ⇒ 解析器抛 `unsupported FREQ=MINUTELY` ⇒ 该自动化**永不触发** —— **正是今天刚查过的那类"幽灵任务"**(有登记、有状态、从不执行)⇒ **⛔ 不做**。
### 11.2 代价证据:**一次运行 = 一个新会话**(从不复用)
| 读数 | 值 |
|---|---|
| `automation_runs` 总运行 / 不同 thread | **74 / 74 ⇒ 1:1** |
| 举例:`b9aaabff`(每日日报) | 跑 **4 次 → 4 个不同会话** |
| 会话表 58 条里,后台自动化会话 | **47 条** |
⇒ 若真按 5 分钟跑:**288 个新会话 / 天**,每次还要起一次 agent、烧一次积分、往会话列表里灌一条 ⇒ 直接撞上"**会话洪泛**"(旧坑 P6)。
### 11.3 🔴 更要紧的一条:**自动任务会话 ≠ 唤醒主会话**
自动化每次开的是**新会话**,它自己跑;**它不会让已存在的主会话"活过来"**。
要真唤醒主会话,那条自动化的 prompt 必须**显式调用** `POST /api/v1/sessions/{id}/reply` —— 而这条 API **只认 live**。
⇒ **绕了一圈又回到同一个硬前提:主会话必须是"桌面当前打开的那一个"。**
### 11.4 能做的三档(按可行性排序)
| 档 | 做法 | 粒度 | 代价 | 判定 |
|---|---|---|---|---|
| **①** | **1 小时自动化**(官方唯一可用粒度)prompt = 写触发戳 + `reply` 投主会话 | **1 h** | **24 会话/天** | ✅ 现成,今天可建 |
| **②** | **外部定时器**(手机快捷指令 / 服务器 cron `47.77.182.89`)→ 走**已建好的 443 通道** → `reply` | **5 分钟可做** | 🔴 **0 个新会话**(只往已有会话投一条消息) | ✅ **唯一能到 5 分钟、且最省**;缺"定时那一端"+凭据载体 ⇒ **需单独评审** |
| **③** | 手写 DB 塞 `FREQ=HOURLY;BYMINUTE=0,5,10…` | 未验证 | 未验证 | ⚠️ 解析器**认** BYMINUTE,但 HOURLY 的 `formatRRule` 不产出它、**调度器是否真按分钟触发未知** ⇒ 只能**先试 1 条并观察是否真触发**;不成就退回 ① |
### 11.5 建议(已定项)
1. ⛔ **不要再往"5 分钟自动任务"上使劲** —— 产品层面不存在这个粒度,硬塞只会得到幽灵任务。
2. **要 5 分钟节奏 ⇒ 走 ②**:定时器放在 **WorkBuddy 外面**(手机侧或服务器),投递走**同一条已验收的 443 通道**。它同时满足三件事:真 5 分钟、不爆会话列表、不烧 288 次积分。
3. **接受 1 小时 ⇒ 走 ①**:一条 recurring 自动化(`FREQ=HOURLY;INTERVAL=1`),prompt 只做两步(写触发戳 + `reply` 唤醒主会话)。
4. ⚠️ **无论哪一档,"主会话必须 live"绕不过** ⇒ 请**固定一个会话并在桌面上一直开着它**;否则 `reply` 只会 409,而改走 ACP 借用会**夺走你正在看的会话**(红线 T2 禁止)。