Back to Qwen Code

cua-driver 0.7.1 相对坐标模式修复

packages/cua-driver/docs/0.7.1-coord-norm-fixes.md

0.19.96.0 KB
Original Source

cua-driver 0.7.1 相对坐标模式修复

PR: https://github.com/QwenLM/qwen-code/pull/6610

CUA_DRIVER_RS_COORDINATE_SPACE=1 开启 0–1000 归一化坐标模式后,多个工具的坐标转换和描述存在缺陷。以下逐一说明。


1. get_window_state / get_desktop_state 返回的 screenshot_width/height 被篡改为 1000

原因normalize_result 在归一化模式下把 get_window_stateget_desktop_state 返回的 screenshot_width/height 强制改写为 1000。设计意图是让模型把截图当作 1000×1000 虚拟网格,直接用 0–1000 坐标。但 elements[].frame 坐标保持真实像素值(如 x=1444),两者矛盾。

表现:模型看到 screenshot_width=1000 但 element frame 坐标远超 1000,拿到了两套不一致的坐标信息。get_desktop_statescreen_width/height 也没被改,同样矛盾。

修复:删掉 normalize_result 的改写逻辑,函数改为 no-op。查询类工具返回真实像素值,模型通过工具 schema 描述和 MCP instructions 知道使用 0–1000 坐标。

2. zoom 后 from_zoom 点击坐标未转换

原因denormalize_argsfrom_zoom=true 时直接 return 跳过了整个转换逻辑。注释说"core 层没有 zoom 图片尺寸,无法转换"——但这个尺寸其实可以从 zoom 工具的返回值中缓存下来。

表现:模型发送 0–1000 归一化坐标(如中心点 500,500),被当作像素值直接传给 zoom_to_window,点击位置完全偏移。

修复

  • 新增 ZOOM_SIZE_CACHE,在 zoom 工具执行后由 ingest_zoom_size 缓存图片的 width/height(keyed by pid)
  • denormalize_argsfrom_zoom 分支改为用缓存的 zoom 图片尺寸做反归一化
  • ToolRegistry::invoke 的 output hook 中增加 ingest_zoom_size 调用

3. from_zoom 的工具描述仍然写着 "pixel coordinates"

原因rewrite_coord_desc 只重写了 input_coord_fields 中列出的坐标字段(x/y)的描述,没有处理 from_zoom 字段本身的描述。

表现:click 工具的 from_zoom 字段描述为 "x and y are pixel coordinates in the last zoom image",模型按此发送像素坐标而非归一化坐标。即使 x/y 的描述已被改为 "0–1000 normalized",from_zoom 的描述与之矛盾。

修复rewrite_coord_desc 中对所有含 from_zoom 字段的工具,将其描述改写为 "x and y are 0–{scale} normalized coordinates in the last zoom image"。

4. 缓存未命中时静默透传归一化坐标

原因denormalize_argsSIZE_CACHESCREEN_SIZEDESKTOP_SCREENSHOT_SIZE 未命中时用 continue 跳过该字段,归一化值原样传给工具。

表现:模型发送 500(归一化中心)但被当作 500 像素处理。坐标错误且不可预测,可能触发意外的误操作,且没有任何报错信息。

修复denormalize_args 返回类型改为 Result<(), String>。缓存未命中时返回明确的错误信息,引导模型先调用对应的查询工具:

  • 窗口级 → "Call get_window_state first"
  • 桌面级 → "Call get_desktop_state first"
  • 屏幕级 → "Call get_screen_size first"
  • zoom 级 → "Call zoom first"

ToolRegistry::invoke 中处理该 Result,未命中时直接返回 ToolResult::error

5. scroll 工具的 x/y 坐标未做归一化转换

原因input_coord_fields 的注释写着 "scroll / page / set_value carry no coordinates → excluded",但实际上 macOS 和 Windows 的 scroll 工具都有 x/y 参数,用于指定滚轮事件的触发位置(不是滚动量)。

表现:归一化模式下模型传 0–1000 坐标给 scroll 的 x/y,被当作像素值处理,滚轮事件投递到错误的位置。

修复:将 scroll 加入 input_coord_fields,window-basis。

6. Linux-only mouse 工具未做归一化转换

原因mouse_button_downmouse_button_upmouse_dragparallel_mouse_drag 四个 Linux 专用工具不在 input_coord_fields 中。它们的 x/y 都是 window-local 坐标。

表现:归一化模式下这些工具的坐标不转换,行为与 click/drag 不一致。

修复

  • mouse_button_downmouse_button_upmouse_drag 加入 input_coord_fields
  • parallel_mouse_drag 的坐标嵌套在 drags[] 数组内,在 denormalize_args 末尾单独处理:每个 drag item 用自己的 (pid, window_id)SIZE_CACHE 获取转换基准;转换 from_x/from_y/to_x/to_ypath[[x,y]]x_from/x_to(fn 表达式域边界)

7. type_text / press_key / hotkey 的 x/y 描述未改写

原因:这三个工具的 x/y 用于 focus-by-pixel(内部委托给 click),input_coord_fields 中没有列出,所以 rewrite_coord_desc 跳过了它们的字段描述。

表现:归一化模式下这三个工具的 x/y 描述仍然写着 "Screenshot-pixel X",模型可能据此发送像素坐标。

修复:将 type_textpress_keyhotkey 加入 input_coord_fields,使其 x/y 描述被重写,同时坐标值也会被正确转换。

8. 多个工具的顶层描述中残留像素坐标措辞

原因rewrite_coord_desc 的顶层描述替换只匹配 "window-local screenshot pixels" 一个固定字符串,但各平台的工具描述中有多种变体:"screenshot pixel coordinates""scaled-image coordinates""true screen pixels""zoom-image pixel coordinates" 等。此外替换后会产生冗余尾部(如 "0–1000 normalized coordinates — the same space get_window_state returns")。

表现:zoom、drag、get_desktop_state 等工具的描述在归一化模式下仍然包含像素相关措辞,误导模型。

修复

  • 扩展替换列表覆盖所有变体
  • 增加冗余尾部清理("the same space get_window_state returns" 等)
  • rewrite_coord_desc 不再跳过空 input_coord_fields 的工具,使 parallel_mouse_dragget_desktop_state 等工具的顶层描述也能被处理
  • protocol.rs 的 MCP instructions 中 "issue a pixel click" 在归一化模式下改为 "issue a coordinate click"