92 lines
4.4 KiB
Markdown
92 lines
4.4 KiB
Markdown
|
|
---
|
|||
|
|
title: Desktop Op 桌面操作模块
|
|||
|
|
created: 2026-05-14
|
|||
|
|
updated: 2026-05-14
|
|||
|
|
type: entity
|
|||
|
|
tags: [module, runtime, agent, backend]
|
|||
|
|
sources: [packages/backend/src/modules/desktop_op/, packages/backend/src/modules/netaclaw/tools/builtin/weixin_send_text.ts, docs/superpowers/specs/2026-05-14-neta-desktop-op-design.md]
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Desktop Op 桌面操作模块
|
|||
|
|
|
|||
|
|
Desktop Op 是 2026-05-14 新增的通用桌面 GUI Agent 模块。它把本机窗口定位、截图、键鼠输入、VLM 验证、队列互斥和审计日志封装成后端模块,当前 MVP 只注册 `WeixinAdapter`,服务于 [[agent-channel]] 的 weixin-db 群聊自动回复。
|
|||
|
|
|
|||
|
|
## 目录结构
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
desktop_op/
|
|||
|
|
├── config.ts
|
|||
|
|
├── controller/admin/ # action_log 与 config 管理 API
|
|||
|
|
├── entity/ # desktop_op_config / desktop_op_action_log
|
|||
|
|
├── runtime/ # 核心运行时、输入、截图、VLM、安全护栏、适配器
|
|||
|
|
└── service/ # DesktopOpService 与配置 bootstrap
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 运行时拓扑
|
|||
|
|
|
|||
|
|
`DesktopOpRuntime.runTask()` 是核心执行入口:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
DesktopTask
|
|||
|
|
-> SafetyGuard 校验 task/app/action
|
|||
|
|
-> AdapterRegistry 选择 AppAdapter
|
|||
|
|
-> WindowLocator 定位并激活窗口
|
|||
|
|
-> adapter.preFlightCheck()
|
|||
|
|
-> adapter.buildSteps()
|
|||
|
|
-> ActionExecutor 逐步执行 clipboard / hotkey / wait 等动作
|
|||
|
|
-> adapter.verifyResult()
|
|||
|
|
-> TaskResult
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
所有任务都接收 `AbortSignal`。运行时在开始、激活窗口后、preflight 后、每个动作前和 verify 前检查中止状态,因此 [[agent-channel]] 删除频道、关闭 weixinReply 或任务超时时可以级联取消。
|
|||
|
|
|
|||
|
|
## 服务层队列与互斥
|
|||
|
|
|
|||
|
|
`DesktopOpService` 提供两个入口:
|
|||
|
|
|
|||
|
|
- `runAndWait(task, timeoutMs)`:同步等待结果,当前由 [[tool-system]] 的 `weixin_send_text` 调用。
|
|||
|
|
- `enqueue(task)`:fire-and-forget 留口,后续可用于异步桌面任务。
|
|||
|
|
|
|||
|
|
队列按 `appId + adapter.queueKey(target)` 分组,同一个微信会话串行执行;真正执行前还会获取全局 `DesktopMutex`,避免多个任务同时争用键鼠。每个 queue key 最多保留 20 个任务,溢出时写 `queue-overflow` 审计日志。
|
|||
|
|
|
|||
|
|
## WeixinAdapter
|
|||
|
|
|
|||
|
|
`runtime/adapters/weixin_adapter.ts` 是当前唯一适配器:
|
|||
|
|
|
|||
|
|
- `appId = "weixin"`,支持 `send-text`。
|
|||
|
|
- 通过 `WindowLocator.findByAppName("Weixin")` 找到未最小化的最大微信窗口。
|
|||
|
|
- preflight 截图并用 VLM 宽松判断当前顶部对话名是否匹配目标群。
|
|||
|
|
- `buildSteps()` 固定生成 `clipboard-write -> ctrl+v -> wait -> enter -> wait`。
|
|||
|
|
- verify 再次截图并用 VLM 检查最新己方消息,但 MVP 中为避免 VLM 误判导致重复发送,build steps 成功后默认按成功处理。
|
|||
|
|
|
|||
|
|
这意味着 Desktop Op 当前不是完整自主 GUI 探索 Agent,而是“适配器主导的确定性动作序列 + VLM 状态验证”。
|
|||
|
|
|
|||
|
|
## 数据模型
|
|||
|
|
|
|||
|
|
| 表名 | Entity | 用途 |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| `desktop_op_config` | `entity/desktop_op_config.ts` | 全局白名单、危险按键、频率上限和默认水印 |
|
|||
|
|
| `desktop_op_action_log` | `entity/desktop_op_action_log.ts` | 每个桌面任务的终态审计,包括 channelId、roomName、modelChannel、状态、耗时和错误 |
|
|||
|
|
|
|||
|
|
`desktop_op_config` 不再保存默认模型渠道;v4 约定模型来自桌面操作 Agent 自己的 `modelChannelId`。
|
|||
|
|
|
|||
|
|
## 与微信双 Agent 的关系
|
|||
|
|
|
|||
|
|
weixin-db 群聊自动回复采用双 Agent:
|
|||
|
|
|
|||
|
|
1. reply agent 读取群消息、决定是否回复,并通过 `delegate_task` 委托。
|
|||
|
|
2. desktop agent 持有 `weixin_desktop` toolset 和 `weixin_send_text` 工具。
|
|||
|
|
3. `weixin_send_text` 从 `_netaRuntime.bizContext.channelId` 和 `currentAgent.modelChannelId` 读取运行时上下文。
|
|||
|
|
4. 工具创建 `DesktopTask(appId="weixin", actionType="send-text")`,交给 `DesktopOpService.runAndWait()`。
|
|||
|
|
5. Desktop Op 激活微信窗口、粘贴、发送并记录 `desktop_op_action_log`。
|
|||
|
|
|
|||
|
|
保存 weixin-db 渠道配置时,后端会自动为 desktop agent 补齐 `weixin_desktop` toolset,并把 `weixin_send_text` 配置为可在子 Agent 中使用且强制走主进程代理。
|
|||
|
|
|
|||
|
|
## 相关页面
|
|||
|
|
|
|||
|
|
- [[agent-channel]] — weixin-db 渠道和双 Agent 回复配置
|
|||
|
|
- [[tool-system]] — `weixin_send_text` 工具和工具路由
|
|||
|
|
- [[netaclaw-module]] — NetaClaw 主模块与外部渠道入口
|
|||
|
|
- [[frontend-architecture]] — 频道管理页的 weixinReply 配置 UI
|
|||
|
|
- [[database-entity-overview]] — desktop_op 表速查
|