OpenCADStudio ↔ WorkBuddy 桥接
用途
把开源 CAD 软件 OpenCADStudio 的 Web/WASM 版集成到 WorkBuddy 右侧面板(内置浏览器的"网页"页签),通过 WebSocket 中继让智能体实时驱动 CAD 绘图。
用户只需在对话区说"画一个法兰",右侧 CAD 就会一笔一笔画出图形,全程可见。
核心价值
- 产出的是真正的 CAD 实体(LINE/CIRCLE/ARC/PLINE/SOLID),可继续编辑、标注、导出 DWG —— 不是生成图片
- 绘制过程实时可见:分组执行 + 每组 zoom_extents,用户能看到从无到有的完整过程
- 支持真彩色填充:SOLID + RGB 真彩色,可还原建筑/机械的真实配色
架构
WorkBuddy 对话(智能体)
↓ 生成 CAD 命令
scripts/ocs.mjs(agent 客户端)
↓ WebSocket ws://127.0.0.1:9090
ws_relay.py(中继,多 host 广播)
↓ WebSocket
host.html(桥接宿主页,侧边栏显示)
↓ 同源 iframe contentWindow
OpenCADStudio(/app/,wasm 48M)
serve_app.py同时托管 CAD 产物(/app/)与桥接页(/agent/),端口 8080host.html内嵌 iframe 加载原样 CAD,用iframe.contentWindow.wasmBindings转发命令- 中继把 agent 与 host 解耦,agent 可多次运行、任意语言
工作流
阶段 1:获取并编译 OpenCADStudio
git clone https://github.com/HakanSeven12/OpenCADStudio.git
cd OpenCADStudio
检查依赖(缺哪个装哪个):
rustc --version # 需要 Rust 1.70+
cargo install trunk # WASM 打包工具
rustup target add wasm32-unknown-unknown
编译(产物约 48MB,首次编译 10~30 分钟):
trunk build --release
产物在 dist/app/。注意:Trunk.toml 里 public_url 必须是 /app/,否则资源路径错乱。
阶段 2:部署桥接层
把本 skill 的 scripts/ 下文件复制到项目里:
<项目根>/
├── dist/app/ # trunk 产物(阶段 1)
└── scripts/
├── serve_app.py
├── ws_relay.py
└── ocs-agent/
├── host.html
└── transport.js
serve_app.py 会自动把 /agent/* 路由到 scripts/ocs-agent/。
阶段 3:启动服务
优先让用户在沙箱外启动(最稳定,不受对话中断影响):
双击 scripts/start_services.bat
或在 agent 内用后台任务(注意:turn_aborted 会杀掉它们,见坑 9):
python scripts/serve_app.py 8080 # HTTP 托管
python scripts/ws_relay.py 9090 # WS 中继
验证:
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/agent/host.html # 期望 200
python scripts/services.py status # 两个端口都 LISTENING
阶段 4:在侧边栏打开 CAD
用 present_files 把 URL 打开到 WorkBuddy 内置浏览器(结果区"网页"页签):
present_files(files: ["http://127.0.0.1:8080/agent/host.html"], cwd: "<项目根>")
不要用 Playwright 启动独立浏览器 —— 会抢走 host 角色,导致用户侧边栏的 CAD 断开。
阶段 5:验证连接
node scripts/ocs.mjs state
期望返回 {"ok": true, "document_id": N, ...}。若返回 no_host,说明侧边栏页面未连上中继,见 references/troubleshooting.md。
阶段 6:绘图
用 scripts/draw_template.mjs 作为模板改写(它已封装全部坑):
node scripts/draw_template.mjs
模板内含:
- req/run/act —— 唯一 request_id、每次读 state 补 document_id/revision
- drawStep(cmds, label) —— 画一组 + zoom_extents 实时刷新视图 + 停顿
- fill(solidCmd, rgb) —— SOLID 实心填充 + RGB 真彩色
- 所有异常都会抛错,不会静默失败
快速命令
node scripts/ocs.mjs state # 读状态
node scripts/ocs.mjs new # 新建文档
node scripts/ocs.mjs run "CIRCLE 0,0 50" # 执行单条命令(自动补 document_id)
node scripts/ocs.mjs entities # 实体统计
node scripts/ocs.mjs --json '{"op":"query","limit":100}'
关键坑(必读)
| # | 坑 | 症状 | 解决 |
|---|---|---|---|
| 1 | request_id 必须全局唯一 | Request payload changed |
加 Date.now()+随机数,不能用固定自增 |
| 2 | new 后 document_id 变 | 图画到旧文档/丢失 | act 每次执行前重读 state,禁用缓存 |
| 3 | 所有修改类 op 都要补 document_id/revision | document_required |
run/action/undo/redo/save/set_properties 全要补 |
| 4 | COLOR 命令是全局渲染色 | 所有实体变同一色 | 分对象上色必须用 set_properties /common/color |
| 5 | properties op 查颜色恒返回 256 | 误判上色失败 | 用 records 查 properties.common.color |
| 6 | 颜色 enum 大写开头 | unknown variant |
{"Index":5} / {"Rgb":{"r":x,"g":y,"b":z}} |
| 7 | SOLID 顶点顺序 | 填充变形/成蝴蝶结 | 左下 → 右下 → 左上 → 右上;三角形重复末点 |
| 8 | modal 会吞操作 | 命令无响应 | 操作前轮询 state,action:close_modal |
| 9 | 服务随对话中断被杀 | 侧边栏一直"重连中" | 让用户在沙箱外双击 start_services.bat |
| 10 | 多 host 抢位 | 请求无人应答 | 中继已改多 host 广播;仍异常则让用户刷新页面 |
参考资源
references/api-reference.md—— 完整控制协议(op 列表、绘图命令、颜色格式、查询校验)references/troubleshooting.md—— 故障排查手册(含 netstat / 进程诊断)references/drawing-cookbook.md—— 绘图配方(机械零件、古建筑、1:1 复刻方法论)scripts/draw_template.mjs—— 可直接复用的绘制脚本地基