Skip to main content
Glama
Yueqi-Wang-795

opencode-gui-bridge

README.md
# opencode-gui-bridge

让 opencode(或任何 MCP 客户端)获得**电脑使用能力**:能看(理解屏幕状态)、能操作(点击/输入/滚动)、能验证(确认操作生效)。

基于 PySide6 + Win32 API + Windows UI Automation + 本地 OCR 实现,零系统级依赖。基础操作全部本地运行,无网络需求(仅视觉 describe 可选配网络 API)。

## 快速开始

1. 解压项目到任意目录(示例 `D:\gui-bridge\`),双击 `setup.bat`,等它显示 `Done.`
2. 在你的 opencode 工作目录放一个 `opencode.json`(内容见「接入 opencode」),把两处路径改成第 1 步的实际路径
3. 重启 opencode
4. 用 AI 对话框直接说:
   - 「列出电脑上的窗口」→ 得到 `list_targets` 结果
   - 「打开记事本,在里面输入你好」→ 会自动执行 打开→绑定→快照→点击→输入→验证

## 安装

```powershell
.\setup.bat
```

脚本一次性完成:创建 `venv` 虚拟环境(已存在则跳过)→ pip 安装依赖 → 跑冒烟测试。看到 `Done.` 即安装成功;失败时它会退出并打印原因。

手动装也是一样的效果:

```powershell
python -m venv venv
venv\Scripts\python -m pip install -e .
venv\Scripts\python tests\smoke_test.py
```

要求:Windows 10/11 + Python 3.10+(安装时勾选 *Add python.exe to PATH*)。

## 接入 opencode

`opencode.json` 放在**你运行 opencode 的工作目录**下(不放在项目里):

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "gui-bridge": {
      "type": "local",
      "command": [
        "D:\\gui-bridge\\venv\\Scripts\\python.exe",
        "D:\\gui-bridge\\server.py"
      ],
      "enabled": true,
      "environment": {
        "SILICONFLOW_API_KEY": "{env:SILICONFLOW_API_KEY}"
      }
    }
  }
}
```

两步改动:

1. 把两个 `D:\\gui-bridge\\...` 换成你的实际路径(`\` 在 JSON 里要写成 `\\`)
2. `SILICONFLOW_API_KEY` 那行:本地 OCR 与点击输入**不需要任何 key**,只有你打算用视觉 describe 才需要配置(见下一节)。没 key 就删掉这行。

验证接入成功:重启 opencode 后,跟 AI 说一句「列出电脑上的窗口」;若 AI 能返回窗口列表,说明 `python.exe` 与 `server.py` 路径配置正确。

## 视觉通道配置(describe 用,可选)

`list_targets` 返回的 `channels.vision` 会标明状态:`ready`(有 key)或 `no-key`(没有)。走 OpenAI 兼容 API,任意厂商:

| 环境变量 | 作用 | 默认 |
| --- | --- | --- |
| `VISION_BASE_URL` | API 地址(OpenAI/DeepSeek/通义/智谱 等任一家) | `https://api.siliconflow.cn/v1` |
| `VISION_API_KEY` | 视觉 key(留空则回退 `SILICONFLOW_API_KEY`) | — |
| `VISION_MODEL` | 视觉理解模型 | `Qwen/Qwen3-VL-32B-Instruct` |
| `VISION_OCR_MODEL` | 视觉 OCR 模型(describe 的 OCR 兜底) | `deepseek-ai/DeepSeek-OCR` |

三种设置方式,任选其一:

**a) opencode.json 内嵌(跟随配置,最推荐)**

```json
"environment": {
  "VISION_BASE_URL": "https://api.siliconflow.cn/v1",
  "VISION_API_KEY": "{env:OPENAI_API_KEY}",
  "VISION_MODEL": "Qwen/Qwen3-VL-32B-Instruct"
}
```

`{env:XXX}` 表示读取你本机已有的同名环境变量。

**b) 系统级持久化**(对所有终端生效):

```powershell
setx VISION_API_KEY "sk-xxxx"
setx VISION_BASE_URL "https://api.siliconflow.cn/v1"
```

设完要重开终端 **和重开 opencode** 才生效。

**c) 只在该次终端会话生效**:

```powershell
$env:VISION_API_KEY = "sk-xxxx"
```

## CDP 通道配置(WebView2 / Tauri / Electron)

Tauri、WebView2、Electron 等 Web 内核应用,UIA 只能看到外层壳,读不到 DOM。开启 CDP 调试端口后,快照会自动走 CDP 通道(元素 id 前缀 `d:`),读取全文是毫秒级。

按应用类型开启调试端口:

| 应用类型 | 方法 |
| --- | --- |
| Chrome/Edge 浏览器 | 启动加参数:`chrome --remote-debugging-port=9222 --remote-allow-origins=*` |
| WebView2(WPF/WinForms/Tauri 内嵌) | 先设环境变量再启动应用:`$env:WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS = "--remote-debugging-port=9222 --remote-allow-origins=*"`,然后启动应用 |
| Electron 应用 | 启动加参数:`your-app.exe --remote-debugging-port=9222` |

```powershell
$env:WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS = "--remote-debugging-port=9222 --remote-allow-origins=*"
Start-Process 目标应用
```

启动后用 `list_targets` 确认:返回的 `channels.cdp` 会显示端口号(如 `9222`)。之后 `snapshot` 自动走 CDP,`act` 自动路由 DOM 操作:

- 读页面全文:DOM innerText,<10ms(OCR 要 1~6s)
- 点击:原生 DOM click(绕过物理 hit-test 覆盖层)
- 输入:Input.insertText 真实输入管线(兼容 Quill 等编辑器)
- 元素坐标:CSS×DPR+窗口位置近似(操作不依赖坐标)

没开启也不影响使用:这类应用会自动降级走本地 OCR 通道,照样能读屏和操作。

## 工具箱:7 个 MCP 工具

| 工具 | 参数 | 作用 | 典型返回 |
| --- | --- | --- | --- |
| `list_targets()` | 无 | 枚举可用窗口 + 4 个通道状态 | `{windows:[{handle,title,x,y,width,height,uia}], channels:{uia,ocr,cdp,vision}}` |
| `focus_target(handle=?, title=?)` | 句柄或标题(子串匹配) | 绑定目标窗口 | `{handle, title, cdp_port, focused, note}` |
| `snapshot(max_items=80, prefer="auto")` | `prefer` 可选 `auto/cdp/uia/ocr` | 界面快照,给出一批带稳定 id 的元素 | 多行文本,如 `[ocr] 元素 15 个` + `o:3 text (y坐标...) 文本` |
| `act(action, target_id=?, text=?, keys=?, x=?, y=?, delta=?, verify=true)` | 动作与目标 | 点击/输入/按键/滚动/回车,含验证 | `{ok, verify, detail}` |
| `wait_change(x=?,y=?,w=?,h=?, text="", timeout=15)` | 区域或文字 | 等待界面变化 / 某文字出现 | `{changed, detail}` |
| `screenshot(name="shot", x=?,y=?,w=?,h=?)` | 区域可省略(默认目标窗口) | 保存截图到 `screenshots/` | 保存路径 |
| `describe(region="")` | 截图文件路径,省略=目标窗口 | 视觉模型描述画面(需视觉 key) | 自然语言描述 |

规则:`snapshot`/`act` 需要在 `focus_target` 之后调用。

### act 动作详解

| action | 参数 | 说明 |
| --- | --- | --- |
| `click` | `target_id` | 点击元素,自动按 id 前缀选择通道 |
| `input` | `target_id`, `text` | 聚焦该元素并输入文本,之后自动 OCR 验证文本是否出现 |
| `press` | `keys` | 组合键,`["ctrl","a"]`、`["enter"]`、`["esc"]` |
| `enter` | 无 | 等效 `press(["enter"])` |
| `scroll` | `delta`(±) (可选 `x`,`y`) | 滚动;给坐标则滚到该点 |

返回结构 `{ok, verify, detail}`:

- `ok`: 动作是否执行
- `verify`: 执行后自动验证的结果
  - `changed` / `matched`:界面确实变了 / 输入内容已确认出现
  - `no_change` / `no_match`:没检测到预期变化(可能动作没生效,建议重新 snapshot 看最新状态)
  - `cdp_insert` / `skipped`:走了 CDP 输入或指定关闭验证
  - `failed`:执行失败,`detail` 会带原因,点击类失败会自动物理重试并附诊断截图路径
- `detail`: 人类可读的结果说明,可能附 `诊断截图: <路径>`

## 架构

```
┌─ Agent (AI)
│   7 个 MCP 工具: list_targets / focus_target / snapshot /
│   act / wait_change / screenshot / describe
├─ server.py      会话编排: 目标窗口绑定, 通道选择, 验证闭环
├─ snapshot.py    统一元素抽象: {id, type, text, bbox, enabled, focused}
│                 通道融合 + 稳定 id (u:路径链 / o:OCR索引)
├─ executor.py    动作路由: click/input/press/scroll + 内置验证
├─ uia.py         UIA 控件树通道 (L1, 毫秒级, 原生应用)
├─ ocr.py         本地 OCR 通道 (L2, 1~6s, WebView 兜底)
├─ win32io.py     Win32 底层: 窗口/鼠标/键盘/截图/PostMessage/PrintWindow
└─ vision.py      视觉模型通道 (L3, 兜底理解, 需 API key)

运行日志写入 `logs/gui-bridge.log`(JSON lines:每次工具调用的耗时/通道/结果)。
```

### 核心设计

1. **AI 只按元素 id 操作,不用坐标**。快照给 id,act 自动把 id 路由到最优通道。
2. **通道自动降级**:CDP → UIA → OCR → 视觉;点击: InvokePattern → PostMessage → 物理。
3. **验证闭环内置**:act 返回 verify=changed/no_match/failed + 原因。
4. **遮挡安全捕获**:OCR 与验证用 PrintWindow 直取目标窗口真实内容,目标被其他窗口盖住也不串内容。

### 元素 id 规则

| 前缀 | 来源 | 示例 | 稳定性 |
| --- | --- | --- | --- |
| `d:` | CDP DOM | `d:0/3/7` | 结构不变则稳定 |
| `u:` | UIA | `u:0/1/3` (从窗口根的子索引链) | 结构不变则稳定 |
| `o:` | OCR | `o:0` (按 y 排序索引) | 每次界面变化后需重取快照 |

`o:` 和界面变化后失效的 `u:`,点击前请先重新 `snapshot` 拿新 id。

## 测试

```powershell
venv\Scripts\python tests\smoke_test.py   # 7 工具 + UIA 全链路(自建测试窗口)
venv\Scripts\python tests\ocr_test.py     # OCR 通道兜底链路
venv\Scripts\python tests\stdio_e2e.py    # 端到端:真实 MCP stdio 会话
```

## 已知限制

- WebView2/Tauri 双层壳 DOM 不暴露给 UIA → 自动走 OCR 通道(实测可完整读屏与操作)
- Windows 可能禁止后台进程抢焦点 → focus_target 会提示,必要时手动点一次目标窗口
- OCR 通道每快照 1~6s(画面静止时快照缓存命中可到亚秒级),是 WebView 应用的主要延迟来源
- 当前仅支持 Windows

Maintenance

ActivityMaintained
ResponsivenessNo issues