qwen-code cua-driver 归一化坐标边界:用 `CUA_DRIVER_RS_COORDINATE_SPACE` 打通 Qwen 0-1000 坐标契约
qwen-code cua-driver 归一化坐标边界用CUA_DRIVER_RS_COORDINATE_SPACE打通 Qwen 0-1000 坐标契约【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code本篇技术指南围绕 qwen-code 仓库中 cua-driver 桌面控制驱动设计文档讲解其归一化坐标边界设计如何通过环境变量将模型侧习惯使用的 0–1000 归一化坐标在统一的授权与分发边界处翻译为平台实际需要的像素坐标。读完本文你将掌握该功能的启用契约、坐标基选择规则、转换公式、覆盖的工具清单、浏览器坐标的 fail-closed 语义以及其底层实现与测试验证方式可直接据此配置或二次开发基于 Qwen-VLcomputer_use的桌面自动化 Agent。背景为什么需要 0–1000 归一化坐标以 Qwen-VLcomputer_use为代表的多模态 Agent 在推理时并不天然输出与屏幕分辨率绑定的像素值而是遵循一种 0–1000 的归一化网格约定坐标被表达为相对于某张截图宽高的比例值例如x500, y500表示位于截图宽高各自的 50% 处。这种方式的好处是模型的坐标输出与具体分辨率解耦同一套推理结果可以在不同尺寸的屏幕上复用。但 cua-driver 的平台工具表面click、drag、scroll 等原生接收的是像素坐标。二者之间需要一个翻译层在 Agent 发送 0–1000 坐标、平台工具消费像素坐标之间完成换算。本文所述的归一化坐标边界正是这一翻译层的完整契约与实现代码位于 coord_norm.rs其文件头注释明确说明它是Opt-in 的 1000×1000 归一化翻译层默认关闭像素语义。契约与进程级开关归一化模式通过环境变量启用属于进程级配置公共工具参数tool arguments无法在调用时开启或关闭它环境变量作用默认值/回退CUA_DRIVER_RS_COORDINATE_SPACE1启用 Qwen 0–1000 坐标契约不设置或非1时保持像素语义默认CUA_DRIVER_RS_COORDINATE_SCALE覆盖归一化满量程即1000×1000中的 1000无效或 0 时回退到 1000满量程可配置的原因在于社区 cookbook 存在 999 与 1000 两种写法Qwencomputer_use使用 1000而mobile_use使用 999。源码中set_coordinate_scale明确拒绝 0避免除零coordinate_scale()读取环境变量时也会过滤非法值与 0 并回退 1000见 coord_norm.rs。值得注意的设计细节是开关与满量程只作为启动默认值注入。coord_norm.rs维护DEFAULT_NORMALIZED与COORDINATE_SCALE两个原子全局量ToolRegistry::new()在构造时将其拷贝进注册表实例字段normalized_coordinates见 tool.rs 与default_normalized()而invoke/tools_list实际读取的是注册表字段而非全局状态——这样测试可以按注册表独立翻转开关而不产生全局竞态同时公开的set_coordinate_space_normalized方法也只在受信任的嵌入宿主构造期使用公共传输层无法触及。转换层的规范放置位置翻译层位于cua-driver-corecrate由ToolRegistry调用。ToolRegistry是 MCP、CLI、daemon、private-worker、replay 与直接 SDK 路径共享的规范授权与分发边界因此转换逻辑不会被任何单一传输绕过。关键的调用链证据位于 tool.rs 的invoke_authorized中先完成授权、同意、录制所需的全部校验authorize_tool_call_with_context等克隆一份public_args保留给授权、同意、录制、replay 与动作证据使用仅在self.normalized_coordinates为真时对私有分发副本args调用coord_norm::denormalize_args完成归一化→像素转换转换后的像素参数才交给平台 worker 分发。这一放置方式由 0.17 SDK 架构决定如果只改造某个 MCP handler 或 daemon 路由其他传输就能绕过契约。设计文档明确断言transforming only an MCP handler or daemon route would let other transports bypass the contract。转换公式与坐标系基归一化到像素的换算是一个线性映射pixel round(normalized / scale * dimension)对应源码实现norm_to_pxcoord_norm.rspub fn norm_to_px(norm: f64, dim: u32, scale: f64) - f64 { (norm / scale * dim as f64).round() }其中dim是目标维度X 轴取宽度Y 轴取高度。反向函数px_to_norm在dim 0时返回 0用于防御异常基。换算的关键前提是以哪张图的尺寸为基。不同动作类型使用不同的坐标基设计文档与denormalize_args的字段表input_coord_fields完全对应动作类型坐标基数据来源窗口本地动作click、drag、zoom 等该窗口最新的get_window_state截图尺寸精确到(runtime, pid, window_id)截图尺寸缓存SIZE_CACHE桌面作用域动作无 pid/window_id 的 click/scroll 等最新get_desktop_state截图尺寸物理像素DESKTOP_SCREENSHOT_SIZE缓存屏幕空间动作move_cursor、set_window_frame最新get_screen_size逻辑尺寸SCREEN_SIZE缓存缩放图像动作from_zoomtrue对应 zoom 结果的缓存尺寸ZOOM_SIZE_CACHE按 pidparallel_mouse_drag每个 drag item 按自身(pid, window_id)独立解析SIZE_CACHE逐项查询verify_state.expect[].window.bounds逻辑屏幕基SCREEN_SIZE为什么move_cursor必须用屏幕基而非窗口基源码注释解释了原因move_cursor移动的是屏幕空间的 Agent 光标叠加层CGEvent screen points它没有 window_id因此必须以逻辑屏幕尺寸为基coord_norm.rs。同理get_desktop_state截图是全屏物理像素桌面作用域点击必须以物理截图尺寸为基这与get_screen_size的逻辑点points语义不同——源码中两组缓存刻意分离测试ingest_get_screen_size_does_not_pollute_desktop_cache专门验证了这一点。窗口基还有一个回退分支当调用带 pid/window_id 但缓存缺失screenshot_w 0时会先判定是否有窗口目标——有则报错引导先调get_window_state无窗口目标桌面作用域则回退到get_desktop_state的截图缓存见denormalize_args中screenshot_w 0分支以及测试denormalize_click_falls_back_to_desktop_screenshot_size。覆盖的输入工具清单归一化转换覆盖以下工具的坐标字段对应input_coord_fields表coord_norm.rs工具被转换的字段坐标基click/double_click/right_clickx,y窗口dragfrom_x,from_y,to_x,to_y窗口zoomx1,y1,x2,y2裁剪矩形窗口from_zoomtrue时用 zoom 缓存scrollx,y投递滚轮事件的位置非滚动量窗口macOS 窗口本地 / Windows 桌面作用域回退mouse_dragx,y窗口mouse_button_down/mouse_button_upx,y窗口type_text/press_key/hotkeyx,y按像素聚焦内部委托 click窗口move_cursorx,y屏幕set_window_framex,y,width,height屏幕parallel_mouse_drag嵌套drags[]中的from_x/from_y/to_x/to_y、x_from/x_to、path点数组逐项按自身(pid, window_id)verify_stateexpect[].window.bounds的x/y/width/height/tolerance_px屏幕parallel_mouse_drag的嵌套结构最复杂每个 drag item 携带自己的pid与window_id转换时逐项从SIZE_CACHE取基path中的[[x,y],...]点序列、函数定义域x_from/x_to也一并转换测试denormalize_parallel_mouse_drag_converts_nested_coords完整覆盖了这三种嵌套形态。转换只作用于调用方实际提供的字段denormalize_args对缺失的坐标字段直接跳过如使用element_index寻址时无 x/y测试denormalize_ignores_missing_coord_fields验证了参数原样透传。浏览器坐标不共享截图基fail-closed浏览器工具的原始坐标是CSS 像素与桌面截图坐标不共享同一个基因此归一化模式无法安全地换算它们。设计文档与源码一致规定归一化模式下browser_click与browser_pointer一旦携带原始坐标字段x、y、to_x、to_y即直接报错并引导调用方改用 fresh browser ref新引用寻址。denormalize_args入口处的硬性检查coord_norm.rsif matches!(tool, browser_click | browser_pointer) [x, y, to_x, to_y] .iter() .any(|field| args.get(*field).is_some_and(Value::is_number)) { return Err( Normalized coordinate mode does not translate browser CSS pixels; use a fresh browser ref instead. .to_owned(), ); }同时schema 重写层rewrite_browser_coordinate_guidance会把浏览器工具的这四个字段描述改为Unavailable in normalized mode; use a fresh browser ref.让模型在调用前就能看到约束而不是运行时才收到错误。tools/list schema 重写与结果字节兼容归一化模式下tools/list返回的工具描述会被重写让模型明确知道这里该发 0–1000 坐标。重写由ToolRegistry::tools_list在normalized_coordinates为真时调用rewrite_coord_desctool.rs。重写内容包括逐字段描述对每个坐标字段插入如X coordinate, 0–1000 normalized to window width (top-left origin).的描述且move_cursor用screen基、其余用window基即使上游 schema 原本没有描述如move_cursor的裸 x/y归一化模式下也会强制插入描述from_zoom描述改写为0–scale 归一化坐标位于该 pid 最近的 zoom 图像中verify_state的 bounds 字段改写为0-1000 normalized against the screen width/height/larger screen dimension.工具顶层描述将多种像素措辞变体window-local screenshot pixels、screenshot pixel coordinates、image-pixel、true screen pixels等统一替换为0–{scale} normalized coordinates (top-left origin)MCP instructionsprotocol.rs的coordinate_terms根据default_normalized()决定使用pixels还是0-{scale} normalized coordinates措辞protocol.rs。像素模式完全保留上游 schema不做任何改写。与之形成对照的是查询结果方向normalize_result目前是显式的 no-op。设计文档解释了一个重要的历史教训——早期版本曾尝试把screenshot_width/height重写为 1000 以提示模型 0–1000 网格但这与保持像素值的elements[].frame、screen_width/height冲突会在同一个 payload 里给出自相矛盾的几何信息。因此现在的策略是查询结果screenshot_width、screenshot_height、accessibility frames、window bounds、cursor positions保持与上游字节兼容模型通过 schema 描述与 MCP instructions 被引导使用 0–1000 坐标。测试normalize_result_is_noop与normalize_result_desktop_state_is_noop均验证了结果不被改写。缓存机制与运行时隔离转换依赖的尺寸基全部来自最近一次状态调用的缓存而非实时截图。四组缓存与写入点缓存键写入工具SIZE_CACHE窗口截图尺寸(runtime_scope, pid, window_id)get_window_state结果中的screenshot_width/heightSCREEN_SIZE逻辑屏幕尺寸runtime_scopeget_screen_size结果中的width/heightDESKTOP_SCREENSHOT_SIZE桌面物理截图尺寸runtime_scopeget_desktop_state结果中的screenshot_width/heightZOOM_SIZE_CACHEzoom 图像尺寸(runtime_scope, pid)zoom结果中的width/height尺寸提取与写入由ingest_window_size、ingest_screen_size、ingest_zoom_size完成它们只在归一化模式下被invoke_authorized调用tool.rs对非目标工具一律忽略测试ingest_ignores_non_get_window_state等验证。所有可变基都按 runtime 私有作用域runtime_scope()隔离runtime_scope()取自current_dispatch_runtime_scope()无则回退legacy因此一个公共 session id 无法读取另一个 runtime 的缓存。窗口尺寸缓存的键特意包含window_id而非仅 pid避免同一进程的多个窗口互相覆盖基SIZE_CACHE注释明确说明了这一点与平台侧resize_registry的 pid-only 键形成对比。失败关闭fail-closed语义如果所需坐标基尚未被观察到缓存缺失分发失败关闭返回带指引的错误要求先调用对应的状态工具而绝不把归一化值当字面像素透传。设计文档明确never treats normalized values as literal pixels因为把 500 当 500px 会把点击落点送到错误位置。denormalize_args对三种缺失基分别给出指引窗口基缺失带窗口目标→Call get_window_state for this window first...屏幕基缺失move_cursor/verify_statebounds→Call get_screen_size first...桌面基缺失桌面作用域→Call get_desktop_state first...from_zoomtrue但无 zoom 缓存 →Call zoom first so the driver knows the zoom image dimensions.。对应测试包括denormalize_errors_when_window_cache_missing、denormalize_errors_when_screen_cache_missing、denormalize_from_zoom_errors_without_cache等。验证与测试设计文档要求的验证分为两层单元测试位于 coord_norm.rs 的mod tests以及 tool.rs 的注册表开关测试覆盖标量换算中点、边界、四舍五入、自定义满量程999 vs 1000、px_to_norm逆运算按轴映射x 用宽、y 用高denormalize_click_uses_width_for_x_height_for_y缺失基失败与指引消息运行时缓存隔离与读写回环zoom 与嵌套坐标parallel_mouse_drag的三种 item 形态浏览器 fail-closed 行为schema 重写含 daemon 的input_schemasnake_case 变体rewrite_handles_daemon_snake_case_input_schema证明重写同时支持 MCP 的inputSchema与 daemon 的input_schema两种键注册表开关registry_coordinate_mode_rewrites_the_published_tool_schema。发布验证必须在每个受支持的桌面平台macOS / Windows / Linux上通过打包后的 MCP 二进制分别实测像素模式与归一化模式两条路径。小结qwen-code 的 cua-driver 通过CUA_DRIVER_RS_COORDINATE_SPACE/CUA_DRIVER_RS_COORDINATE_SCALE两个进程级环境变量在ToolRegistry这个所有传输共享的规范边界处插入了 0–1000 归一化坐标翻译层契约清晰像素语义默认归一化显式开启满量程可配以兼容 999/1000 的 cookbook 差异基选择严谨窗口/桌面/屏幕/zoom 四种坐标基各归其位缓存按 runtime 作用域隔离双层提示schema 描述与 MCP instructions 引导模型发归一化值查询结果保持字节兼容避免几何自相矛盾安全优先缺基即失败关闭浏览器 CSS 像素直接拒绝绝不把归一化值当像素透传验证完备单元测试 全平台打包 MCP 双模式发布验证。对于需要在 qwen-code 生态中接入 Qwen-VLcomputer_use风格桌面控制的开发者启用该契约只需在启动时设置CUA_DRIVER_RS_COORDINATE_SPACE1并保证模型在每次坐标动作前先获取对应的窗口/屏幕/桌面状态快照——这正是该设计希望 Agent 遵循的正确调用序列。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考