news 2026/9/13 15:25:44

cua-driver 兼容性夹具(Compatibility Fixtures)解析:用快照锁住跨语言 SDK、CLI 与 MCP 的公开契约

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
cua-driver 兼容性夹具(Compatibility Fixtures)解析:用快照锁住跨语言 SDK、CLI 与 MCP 的公开契约

cua-driver 兼容性夹具(Compatibility Fixtures)解析:用快照锁住跨语言 SDK、CLI 与 MCP 的公开契约

【免费下载链接】cuaScale computer-use 2.0 with open-source drivers, cross-OS fleets, and benchmarks for training, evaluation, and data generation.项目地址: https://gitcode.com/GitHub_Trending/cua/cua

导读

本篇文章围绕 cua-driver 仓库中libs/cua-driver/compat-fixtures/目录展开,剖析这一套"兼容性夹具(compatibility fixtures)"的设计思路与工程实践:它以cua-driver-rs-v0.12.6发布版为基准,把 Python / TypeScript SDK 的导出与签名、CLI 帮助与 manifest 字段、MCP 初始化与工具列表等稳定公开契约固化成 JSON 快照,并通过 Rust / Python / TypeScript 三套测试在每次构建时校验"新版本是否仍然兼容旧契约"。读完本文,你将理解这套夹具锁定了哪些契约面、如何做"语义级"而非"进程级"的对比校验、什么样的变更被允许(增量新增)、什么样的变更必须走显式兼容决策(破坏性修改),以及 RFC 3682 与 RFC 2549 两条已接受变更在夹具中的具体落地方式。

一、为什么原生驱动需要"兼容性夹具"

cua-driver 是一个跨平台 computer-use 自动化驱动,其 SDK 并非单一语言实现:底层是 Rust 原生核心与生成绑定(generated bindings),上层同时暴露 Python、TypeScript 两个 SDK 语言面,对外还提供 CLI 子命令与 MCP JSON-RPC 服务。多语言、多入口意味着同一个功能面会同时出现在__init__.py.d.ts声明、--help输出和tools/list响应中——任何一个入口发生无意的漂移,都会在升级后静默破坏下游调用方的代码。

compat-fixtures 正是为此设计的"契约保险丝":它从**发布标签(release tag)**而非当前工作区提取快照,锁住选定字段后,任何后续开发只要触发了契约变化,CI 就会立即报告。这套机制的价值在于:

  • 契约可被机器校验:快照是结构化 JSON,测试逐字段比对语义,不依赖人工 review 记忆;
  • 变更可被显式决策:新增是默认允许的,删除或修改必须经过明确的兼容决策并同步更新夹具;
  • 多语言同步受控:Rust、Python、TypeScript 三套测试读取同一套夹具,避免某一语言面悄悄偏离基线。

二、快照基线:从发布标签提取的 0.12.6 契约

夹具锁定的是cua-driver-rs-v0.12.6发布标签,对应提交为9eb1f481b8a12cd6ffda2ad5af21653a9e5aa9e5。快照的生成来源在 compat-fixtures/README.md 中明确列出:

  • 发布标签对应的包源码(release-tagged package sources);
  • 生成绑定(generated bindings);
  • cua-driver --help输出;
  • cua-driver manifest输出;
  • MCP JSON-RPC 实际响应。

一个关键设计是:夹具锚定的是"语义字段"而非"整进程输出"。测试有意排除了可执行文件路径、socket 路径、PID、会话标识符、平台相关散文(platform-specific prose)以及其他易变值。这样做的直接好处是,快照不会因为测试环境差异(如 macOS 与 Linux 的默认 socket 路径不同)而产生虚假失败。

另一个精妙之处在于版本号字段只校验"形状"而非冻结值:夹具不会把版本号锁死为0.12.6,而是只校验其满足语义化版本(semver)格式。原因正如 README 所写——一个兼容的后续版本必须改变版本号,若把版本号冻结反而会让每次发布都触发一次无意义的契约变更。

三、四个 JSON 快照:分别锁住哪一层契约

目录下四个 JSON 文件各自负责一个契约面,下面逐一展开。

3.1python-package.json:Python 包导出与可调用签名

该快照记录三组内容(见 python-package.json):

包根导出(package_root_exports):共 51 个符号,覆盖类型与函数两类:

  • 类型/常量:CaptureScopeClickButtonClickInputDriverOptionsDriverErrorDriverExecutionModeDriverMetadataPlatformSessionStateOutputToolResult等;
  • 函数与模块级 API:__version__current_mac_os_permission_statusget_binary_pathopen_mac_os_screen_recording_settingsrequest_mac_os_permissionsrun_cua_driver

构造器签名(package_constructor_signatures):锁住类方法_connect_python_sdk(cls, socket_path)_create_python_sdk(cls, options = None)两个内部构造入口。

CuaDriver 方法集(cua_driver_methods):锁住 25 个公开方法的完整签名,包括异步动作与查询:

  • 会话管理:start_session/get_session_state/end_session/escalate_session
  • 桌面操作:clickdragscrollhotkeypress_keytype_textmove_cursorget_cursor_positionget_desktop_stateget_screen_size
  • 生命周期:connect/connect_with_client_kind/create/create_with_client_kind/shutdown/socket_path/is_available/execution_mode/metadata/list_tools_json

click为例,其冻结签名为async click(self, input: cua_driver._native_contract.ClickInput) -> cua_driver._native_contract.ActionResult——注意返回类型是ActionResult而非通用ToolResult,这正是 RFC 3682 破坏性变更后的形态(详见第六节)。

3.2typescript-package.json:子路径导出、声明导出与 CuaDriver 声明

该快照锁住四个层面(见 typescript-package.json):

package_exports(包子路径导出):锁住三个入口的解析条件——根入口.指向dist/index.d.ts/dist/index.js./embedded指向dist/embedded.*./electron指向dist/electron.*。这意味着包的"三入口布局"本身就是契约的一部分,不允许在后续版本中悄然移除。

root_declaration_exports(根声明导出):约 53 个符号,除与 Python 对应的类型外,还包括 TypeScript 特有的CuaDriverInterfaceCuaDriverLikeDriverError_TagsEmbeddedCuaDriverHostInterfaceEmbeddedCuaDriverHostLikeSdkClientKind等。

cua_driver_declarations(生成的 CuaDriver 声明方法):锁住静态构造器与核心方法的声明文本,例如:

  • static connect(socketPath: string | undefined): CuaDriverLike;
  • static create(options: DriverOptions | undefined): CuaDriverLike;
  • callTool(name: string, argumentsJson: string, asyncOpts_?: { signal: AbortSignal; }): Promise<ToolResult>;
  • shutdown(asyncOpts_?: { signal: AbortSignal; }): Promise<void>;

注意asyncOpts_上的{ signal: AbortSignal }——异步取消能力也被视为契约的一部分被锁定。

entrypoint_declarations(各入口的声明内容):进一步细化到index.d.tsexport * from "./native/index.js"与 default 导出)、embedded.d.ts(必须暴露EmbeddedCuaDriverHostEmbeddedDriverConnectionEmbeddedPermissionMode)、electron.d.ts(必须暴露 macOS 权限相关 API:MacOSPermissionStatusrequestMacOSPermissionshasRequiredMacOSPermissionsopenMacOSScreenRecordingSettings)。

3.3cli.json:CLI 帮助目录与 manifest 字段

该快照锁住 CLI 的稳定面(见 cli.json):

help_lines:锁住--help输出的头部与子命令目录,包括 "cross-platform computer-use automation driver" 描述行,以及mcp, list-tools, describe, call, serve, stop, revoke, status, config, telemetry, recording, update, check-update, doctor, diagnose, permissions, autostart, skills, manifest共 18 个子命令。

manifest:锁住cua-driver manifest输出的关键字段:

  • schema_version: "1"binary_version_format: "semver"
  • mcp_args: ["mcp"](MCP 的调用参数形式);
  • 各子命令的参数目录,如mcp--socket(string)、--grant(repeatable-string)、--claude-code-computer-use-compat(flag)、--embedded(flag)、--host-bundle-id(string);
  • serve--permission-mode--capability-manifest--approve-capability-manifest--session-policy--approve-session-policy--no-permissions-gate--dangerously-bypass-approvals等;
  • call的两个位置参数tool(positional-string)与json-args(positional-json),以及--screenshot-out-file--socket
  • manifest自身的--prettyflag。

3.4mcp.json:MCP 初始化、工具列表与错误类别

该快照锁住 MCP 服务的协议面(见 mcp.json):

  • initializejsonrpc: "2.0"protocol_version: "2025-06-18"、能力键["tools"]server_name: "cua-driver",且 server 版本号只校验 semver 形状;
  • tools_listschema_version: "1"capability_version: "1",以及 7 个必备工具——list_appslist_windowsget_window_statelaunch_appclicktype_textpress_key。同时针对click工具锁定了其字段集合:namedescriptioninputSchemaannotationscapabilitiesrisk
  • unknown_method_error:方法不存在时的错误类别被锁定为code: -32601message: "Unknown method: compatibility/unknown"——这里特意用一个固定方法名做基准,确保错误响应的结构(而非具体动态内容)稳定;
  • tool_call:工具调用结果必须包含contentisErrorstructuredContent三个字段。

四、apps/:三语言基线应用,验证"不开守护进程也能用"

除了 JSON 快照,apps/目录还冻结了三份未修改的基线应用源码(见 apps/README.md),CI 会针对候选包(candidate packages)实际编译并运行它们。

三个应用刻意只使用"发布版连接构造器 + 端点访问器 + 语言专属清理操作"三件套,且不需要运行中的守护进程:构造兼容客户端并读取其选中的端点是无副作用的本地产物。

Python(apps/python/app.py):

from cua_driver import CuaDriver driver = CuaDriver.connect(None) endpoint = driver.socket_path() if not endpoint.strip(): raise RuntimeError("default endpoint must be selected") print(endpoint)

Rust(apps/rust/src/main.rs),依赖指向工作区内的cua-driver-sdkcrate(见 Cargo.toml):

use cua_driver_sdk::CuaDriver; fn main() { let driver = CuaDriver::connect(None).expect("create compatibility client"); let endpoint = driver.socket_path(); assert!(!endpoint.trim().is_empty(), "default endpoint must be selected"); println!("{endpoint}"); }

TypeScript(apps/typescript/app.mjs),从@trycua/cua-driver导入,并显式调用uniffiDestroy()清理:

import { CuaDriver } from "@trycua/cua-driver"; const driver = CuaDriver.connect(undefined); const endpoint = driver.socketPath(); if (!endpoint.trim()) throw new Error("default endpoint must be selected"); console.log(endpoint); driver.uniffiDestroy();

三个应用验证的是同一个事实:connect(None/undefined)必须能在无守护进程的前提下返回默认端点。由于三者完全一致地断言"默认端点必须非空",任何破坏默认连接行为的改动都会在 CI 的三语言维度上同时失败。

五、测试如何消费夹具:三套"语义比对"实现

夹具本身不产生约束力,真正起作用的是消费它们的测试。仓库中三套测试分别从各自语言面的视角校验契约,这里以 Rust 测试为主线展开(compatibility_contract_test.rs)。

5.1 Rust:真实运行二进制 + JSON-RPC 会话

Rust 测试通过include_str!cli.jsonmcp.json编译进测试二进制,然后用Command真实执行cua-driver --helpcua-driver manifest

  • help 校验:遍历夹具中的help_lines,断言帮助输出包含每一行(assert!(help.contains(line)));
  • manifest 校验:对比schema_version,用semver::Version::parse验证binary_version仍是合法语义化版本,并断言mcp_invocation.args == ["mcp"]且 command 为非空可执行路径;
  • 子命令参数校验:对 manifest 中每个子命令的每个参数(name, type)对,在真实输出中查找匹配项——这正是"只允许新增、不允许删除"的机械化表达;
  • MCP 协议校验:测试通过RawDriver::spawn()拉起真实驱动,依次发送initializetools/listcompatibility/unknowntools/call四组 JSON-RPC 请求,逐一断言协议版本、能力键、必备工具、click工具字段、-32601错误类别以及工具结果三字段(content/isError/structuredContent)全部与夹具一致。

此外还包含两个平台分支测试:

  • 非 macOS 上验证--directMCP 运行时与发布协议契约一致;
  • macOS 上验证显式--direct模式下权限工具只读(direct_capture_status: "not_checked")且拒绝 overlay 工具(拒绝码facility_unavailable)。

5.2 Python:AST 静态解析,不运行进程

Python 测试(test_compatibility_contract.py)采用纯静态 AST 比对:用ast.parse解析src/cua_driver/__init__.pywrapper.py_native.py,把函数签名渲染成字符串后与夹具比对。这种方式的优点是零进程开销、不受运行时环境影响,且能精确锁定"形如async click(self, input: ...) -> ActionResult"的声明细节。测试同时断言__all__中的导出集合是夹具导出集的超集(set(expected) <= actual)——再一次落实"只增不减"原则。

5.3 TypeScript:读取产物声明文件

TypeScript 测试(compatibility-contract.test.mjs)直接读取构建产物:比对package.jsonexports映射、dist/native/cua_driver_contract.d.tscua_driver_sdk.d.ts中提取的声明导出集合、规范化后的CuaDriver方法声明文本,以及index.d.ts/embedded.d.ts/electron.d.ts三个入口必须包含的导出片段。它还额外验证了新版原生窗口方法的类型化输出,例如listApps(input: ListAppsInput, asyncOpts_?: { signal: AbortSignal; }): Promise<ListAppsOutput>

六、两条已接受的契约变更:夹具如何演进

夹具不是"一成不变的枷锁",它区分了两种变更并给予不同待遇。

6.1 RFC 3682:一次有意的破坏性 SDK 修订

RFC 3682(Typed native-window SDK flow and explicit click addressing)接受了一次有意的破坏性变更:旧的click只接受 x/y 坐标且返回通用结果,无法表达元素 token 或后台投递;新契约要求ClickInput必须包含:

  • ActionTarget(明确的窗口或桌面目标);
  • ClickPosition(坐标快照绑定的元素 token,二选一的 sum type);
  • 显式的InputDeliveryMode(后台 / 前台)。

同时click直接返回ActionResult,工具拒绝时抛出DriverError.Tool。该变更落地后,Python 的click签名同步更新,TypeScript 基线则没有冻结该方法(因此不受影响);夹具中其余冻结的包签名、CLI/MCP 快照与基线应用保持不变。测试覆盖了新的签名以及类型化原生窗口的发现(list_appslist_windows)与观察(get_window_state)方法。

这一案例说明夹具的运作逻辑:破坏性变更本身被允许,但必须以 RFC 形式显式决策,并在夹具中留下痕迹——python-package.jsonclick的返回类型变为ActionResult,正是该决策的冻结证据。

6.2 RFC 2549:一个纯新增的 CLI flag

与上述不同,RFC 2549 带来的cua-driver mcp --direct属于纯新增:裸mcp行为保持平台定义(Windows / Linux 直接运行,macOS 为签名应用服务),--socket继续选择显式服务。由于夹具测试采用"候选参数集合包含夹具参数集合"的语义比对,这个新增 flag不需要重写冻结的cli.json基线也能通过校验——这正是"语义比对而非整进程输出比对"的设计回报:新增是零成本兼容,删除才需要成本。

七、工程启示:把"兼容性"变成可测试的资产

回顾整套机制,可以提炼出几条可复用的工程原则:

  1. 从发布标签提取基线,而不是从主干提取——快照代表"用户实际在用的契约",而非"团队想要的状态";
  2. 锁定语义字段而非进程输出——排除路径、PID、平台散文等易变值,让快照跨平台、跨环境稳定;
  3. 版本号只校验形状(semver)——避免兼容性测试与版本递增相互打架;
  4. 新增默认放行,删除/修改必须显式决策——通过子集/超集断言(expected <= actual)把这一策略直接写进测试;
  5. 多语言面共享同一套夹具——Rust、Python、TypeScript 各自动态的测试读取同一批 JSON,任何语言面漂移都会立刻暴露。

对于任何维护多语言 SDK、CLI 与协议服务的项目而言,libs/cua-driver/compat-fixtures/都是一个可以直接借鉴的"契约保险"范式:它让"我们不破坏下游"从一句口头承诺,变成了 CI 中每一次构建都会自动执行的断言。

【免费下载链接】cuaScale computer-use 2.0 with open-source drivers, cross-OS fleets, and benchmarks for training, evaluation, and data generation.项目地址: https://gitcode.com/GitHub_Trending/cua/cua

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 15:25:26

智能任务自动化协同AI工作流:规则引擎+多Agent实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 15:23:11

墨子活动报名系统v2.3.0:轻量级PHP闭环管理实践

简介&#xff1a;本资源是一套基于PHP开发的轻量级活动报名管理系统源码&#xff08;v2.3.0&#xff09;&#xff0c;面向Web开发初学者、中小型活动组织者及PHP全栈实践者&#xff0c;解决线下/线上活动从发布、报名、审核到数据汇总的一站式管理需求。压缩包共2000个文件&…

作者头像 李华
网站建设 2026/9/13 15:22:23

6个月机器人工程师实战成长路线图

1. 这不是速成班&#xff0c;而是一份真实可行的工程师成长路线图“如何在6个月内成为一名机器人工程师”——看到这个标题&#xff0c;很多人第一反应是怀疑&#xff0c;甚至觉得是标题党。但作为带过三十多个机器人方向实习生、亲手搭建过工业分拣产线、也调试过服务机器人导…

作者头像 李华
网站建设 2026/9/13 15:20:10

编程语言的困境:为何类型、性能与生态之争至今无解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 15:19:05

MATLAB实现VMD信号分解与故障诊断实战

1. 特征模态分解&#xff1a;信号处理领域的瑞士军刀在工程信号分析领域&#xff0c;我们常常面对这样的场景&#xff1a;一段混杂着多种振动成分的机械故障信号&#xff0c;或者掺杂着不同频段生物电信号的EEG数据。传统傅里叶变换虽然能告诉我们信号包含哪些频率成分&#xf…

作者头像 李华
网站建设 2026/9/13 15:18:07

gVisor 安装指南:apt 仓库、tarball 手动安装与 release 渠道详解

gVisor 安装指南&#xff1a;apt 仓库、tarball 手动安装与 release 渠道详解 【免费下载链接】gvisor Application Kernel for Containers 项目地址: https://gitcode.com/GitHub_Trending/gv/gvisor 本篇指南基于 gVisor&#xff08;Application Kernel for Container…

作者头像 李华