ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

qwen-code Cua Driver 集成边界选型解析:为什么 Agent 走 MCP/CLI,而应用 SDK 走 UniFFI

qwen-code Cua Driver 集成边界选型解析:为什么 Agent 走 MCP/CLI,而应用 SDK 走 UniFFI qwen-code Cua Driver 集成边界选型解析为什么 Agent 走 MCP/CLI而应用 SDK 走 UniFFI【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读本文围绕 qwen-code 仓库中 Cua Driver 的集成边界决策文档why-cua-driver-uses-mcp-instead-of-uniffi.md系统讲解 Cua Driver 如何把被 Agent 使用的工具与被应用导入的 API两条产品线彻底分开Agent 边界继续使用 MCP/CLI应用 SDK 则改用 Rust 实现 UniFFI 绑定分发。读完本文你将掌握 MCP 与 UniFFI 各自回答的工程问题、当前仓库中 Rust SDK 的真实调用链CuaDriver.create()同进程 /connect()走 daemon socket、UniFFI 生成与打包的边界含 Python wheel 与 npm 平台包机制以及直接嵌入 GUI 引擎为何仍被明确排除在现状之外。说明该文档标记为部分被 RFC 2447 取代。RFC 2447 保留 MCP 作为 Agent 边界但把导入 SDK 拓扑替换为同进程运行时并使 MCP 成为 SDK 的下游消费者本文以关联文档主体为准并在涉及处标注差异。一个常被混淆的问题MCP 与 UniFFI 并非同一层很多讨论把Agent 该不该用 MCP和应用该不该用 UniFFI当成同一个二选一问题。关联文档明确指出这是一个错误框架MCP 和 UniFFI 解决的是不同边界二者不是竞争协议而应被同时采用。集成表面消费者公开形态运行时可移植性由谁提供Cua 作为 Agent 的 MCP 或 CLICodex、Claude Code、其他 Agent、Shellqwen-cua-driver mcp与qwen-cua-driver callMCP 与可执行协议本身已可被任何具备 MCP 能力的运行时直接使用Cua 作为被导入的 SDKPython、TypeScript、Swift、Kotlin 等应用cua_driver或qwen-code/cua-sdkPython 与 Node 通过实验性 UniFFI 绑定调用共享的 Rust daemon-client 实现MCP 回答的问题是Agent 或进程如何跨服务边界调用一个工具UniFFI 回答的问题是应用代码如何用多种语言调用同一个 Rust 库实现一个产品完全可以同时支持两者MCP 保持语言无关的 Agent 边界UniFFI 绑定让应用开发者宿主或组合 Rust 服务端/客户端实现。采纳 UniFFI 既不要求、也不应该移除 MCP。从仓库现状看这一分工已落实到实现层面cua-driver-contract/src/lib.rs 开篇即声明该 crate 刻意不包含任何传输或平台实现cua-driver-sdk则是规范化的类型化 SDK 与 UniFFI 导出边界其模块注释明确写道MCP 与 daemon 传输只是下游适配器而非并列的契约见 cua-driver-sdk/src/lib.rs。决策要点五条边界原则关联文档给出的最终决策共五条是理解整套架构的纲领保留 MCP 与 CLI 作为规范的 Agent 边界。接入一个 MCP 能力的 Agent不需要安装任何 Cua 语言包。cua-driverPython与qwen-code/cua-sdkTypeScript改为 Rust 实现 UniFFI 绑定的应用 SDK。移除其语言原生 MCP facade因为那是在重复 Agent 运行时本就提供的运行时中立协议客户端。这是发布前的刻意破坏性变更breaking change。导出全部类型化工具的共享 Rust 请求记录与共享类型化结果。动作类工具使用封闭的跨平台ActionResult更丰富的观测载荷仍保留在ToolResult.structured_json中活动注册表用规范的 Rust 结果类型对二者做校验。UniFFI 作为 SDK/服务组合架构使用而不是 Agent MCP 边界的替代品。第一个切片导出共享 Rust daemon 客户端供应用自有的服务端组合。不宣称直接引擎嵌入direct engine embedding今天已经就绪。daemon 持有的状态、权限身份、OS 事件循环行为仍需一份显式嵌入设计。第 5 点在关联文档中反复强调仓库代码也与之吻合cua-driver-sdk同时提供CuaDriver::create在导入进程内拥有平台运行时与CuaDriver::connect临时兼容构造器走已发布的 daemon-client 拓扑两条路径暴露同样的类型化操作见 cua-driver-sdk/src/lib.rs。Agent 集成表面MCP/CLI 是唯一规范入口Agent 侧的架构非常直接Codex / Claude / 其他 Agent - 该 Agent 运行时自带的 MCP 客户端 - qwen-cua-driver mcp - native driver daemon - OS APIs Shell 或自动化脚本 - qwen-cua-driver call - native driver daemon - OS APIsMCP 本身已定义工具发现、调用、结果与错误语义并且跨语言运行时通用。一个 Python Agent 和一个 TypeScript Agent 可以消费同一个 MCP 服务端而不需要 Cua 为任一 Agent 生成协议客户端——为 Python/TypeScript 再生成一层包装并不会让这条表面更运行时中立。examples/agent-sdks/README.md 用可执行示例把这条表面具体化了Claude Agent SDK 的 Python 与 TypeScript 示例都支持--route native进程内自定义工具与--route mcpAgent SDK 自带 MCP 客户端两种路由而Codex SDK 不暴露直接的自定义工具回调其 Cua Driver 示例因此一律走 MCP而不是发明一个特制 native 适配器。两个 Agent SDK 收到的都是同一份 stdio MCP server 声明自行发现 driver 工具没有任何一个示例导入生成出来的 Cua 客户端。这正是决策第 1 条O(1) 实现服务 N 个运行时的直接证据。CLI 的子命令词汇仓库中 cli.rs 完整定义了 CLI 的入口形态与文档中的 Agent/Shell 双路径一一对应qwen-cua-driver → mcp server默认 qwen-cua-driver mcp → mcp server显式 qwen-cua-driver list-tools → 打印全部工具名与描述 qwen-cua-driver describe tool → 打印工具 schema qwen-cua-driver call tool [json-args] → 调用工具并打印结果 qwen-cua-driver tool [json-args] → call 的简写snake_case 名其中mcp子命令还支持--socket显式指定 daemon socket/pipe 路径、--direct在本 MCP 进程中持有运行时macOS 上属于显式的 TCC 权限归属选择与--socket互斥、--claude-code-computer-use-compat注册窗口级 JPEG 兼容screenshot工具等选项见 cli.rs。对一次性 Shell 自动化与 Agent 运行前后的确定性生命周期调用来说CLI 仍是实用入口。应用 SDK 表面从薄 MCP 门面到UniFFI 绑定 Rust 实现被移除的旧架构在本次变更之前Python/TypeScript 包是薄 MCP 门面application - 生成的 Python 或 TypeScript 方法 - 小型语言原生 MCP transport - qwen-cua-driver mcp - native driver daemon - OS APIs新架构本次变更后导入型 SDK 的结构是application - 生成的 UniFFI 绑定 - libcua_driver_sdk - 导出的类型化接口 - 结果归一化与错误映射 - 共享 daemon framing、超时、观测元数据 - native driver daemon - OS APIs这里才是O(1) 实现对 N 个运行时论点真正成立的地方产品行为在 Rust 中实现一次导出到 N 个语言运行时而无需在每种语言里维护 N 份行为化客户端。关联文档也诚实指出每个平台、每种架构仍然存在原生产物、加载器、签名与 CI 工作所以打包并非字面上的恒定成本关键收益是行为与接口不会在每种语言中被独立重复实现。实现层面SDK 调用的是 daemon 的直接 socket 协议而不是 MCP。CLI、MCP 代理与 UniFFI 库现在都从cua-driver-core导入同一份 Rust request/response 与 socket 实现因此超时或 framing 的修改不会因语言不同而漂移见 cua-driver-sdk/src/lib.rs 对cua_driver_core::daemon的引用。公共入口词汇包名本身就是 SDK 入口不再需要传输后缀运行时Rust 实现的应用 SDKAgent 集成方式Pythoncua_driver在 Agent 运行时中配置qwen-cua-driver mcpTypeScriptqwen-code/cua-sdk在 Agent 运行时中配置qwen-cua-driver mcp不存在公开的/sdk、/mcp或/native入口。Native描述的是私有生成加载器与平台库而不是产品 API。Python 的_native模块与 TypeScript 的dist/native目录保持私有实现路径因为 UniFFI 输出需要与其平台库同置Python 侧可见 python/src/cua_driver/init.py包文档明确写着Agent 应直接配置 qwen-cua-driver mcp而不是导入语言 MCP facadeTypeScript 侧 typescript/src/index.ts 的模块注释与此完全一致。两个构造器create 与 connectSDK 的两种构造方式对应两种运行时形态CuaDriver.create()在导入应用中执行桌面行为不要求 daemon同进程运行时。connect()socket 背靠背为外部客户端与有意使用已安装宿主的有权限身份保留daemon-client 拓扑。应用可以在两种 SDK 模式之上构建 MCP 或 HTTP 服务端传输始终位于同一份公开 SDK 契约之下游。Python 侧从._native直接导入CuaDriver、CuaDriverSession、ToolResult、DriverMetadata等符号见 python/src/cua_driver/init.pyTypeScript 侧把CuaDriver.create等工厂方法绑定到SdkClientKind.Typescript以标记导入方运行时见 typescript/src/index.ts。SDK 具体增加了什么以及没有增加什么关联文档用一个精确的清单划清了 UniFFI 表面的边界。增加一个同进程的 Rust 桌面运行时、生命周期实现、错误映射与结果归一化供 Python 与 Node 共用为全部 14 个已发布类型化请求记录生成的绑定从活动处理器返回的同一份 Rust 记录生成的规范类型化会话结果一个开放的call_toolJSON 逃生舱供运行时与服务端适配器使用。没有增加Agent/运行时互操作能力——因为 MCP 已经提供每个原生 OS/架构产物的自动发布。CuaDriver.create()在导入进程中执行桌面行为且不依赖 daemonsocket 背靠背的connect()构造器继续为外部客户端和有意使用已安装宿主的有权限身份保留。应用可以在任一 SDK 模式上构建 MCP 或 HTTP 服务端传输始终位于同一份公开 SDK 契约的下游。传输中立的 ToolResult 信封ToolResult是文档第 3 条决策在代码中的落点。它被定义为uniffi::Record字段包括text、imagesImageContent列表携带mime_type与data_base64、structured_json、is_error、error_code、action: OptionActionResult、verification: OptionVerifyStateOutput、degraded与raw_json见 cua-driver-sdk/src/lib.rs。这说明混合 MCP 内容仍是传输信封类型化结构化结果不抹掉文本、图片、拒绝、降级结果或诊断。ActionResult本身是封闭的跨平台契约每个成功的动作返回一个封闭的structuredContent对象例如{ effect: confirmed, route: accessibility, delivery: {mode: background}, evidence: [{kind: value_readback}] }effect与route必填。effect取值为confirmed、partial、unverifiable、suspected_noop、refusedroute取值为accessibility、synthetic_events、global_input、dom、trusted_input。契约刻意封闭不回显选择器、坐标、scope、目标、平台传输名、诊断指针或旧的verified布尔值详见 action-result-contract.md。动作后验确认由独立的verify_state工具承担其终态satisfied是唯一成功状态。契约 crate 用ACTION_RESULT_TOOLS常量集中维护这 23 个动作工具名单含click、type_text、press_key、hotkey、browser_type等见 cua-driver-contract/src/lib.rs保证 MCP schema 广告、运行时校验、SDK 归一化与执行缝不会漂移。兼容性与迁移一次刻意的破坏性变更把 UniFFI 提升到包根是一个对预发布语言 API 的刻意破坏性变更Python 移除AsyncCuaDriver、CuaDriver.stdio()、*Args类与传输类替代品是同步的 Rust 实现 SDK 对象CuaDriver通过CuaDriver.connect(...)创建。TypeScript 移除等价的 async facade 与 stdio 传输。应用消费者把类型化调用迁移到生成的 UniFFI 输入记录。Agent 集成完全移除 Cua 语言包客户端改为通过 Agent SDK 已有的 MCP 支持配置qwen-cua-driver mcp。关联文档特别提醒包与运行时兼容性比 API 签名更难保持。原生绑定在 SDK 连接 driver 之前就可能引入失败模式包必须为每个受支持的 OS 与架构包含兼容库加载器必须能找到该库并满足平台签名与安全策略原生产物必须在每个受支持宿主包括基于 Node 的桌面运行时中工作导入时的原生失败需要一条已定义的降级路径。文中给出一个具体场景Windows ARM64 上的 Electron 应用。当前 TypeScript SDK 可以纯 JS 加载并启动已安装的 driver若 UniFFI 成为唯一传输同一导入可能要求匹配的原生产物与加载器——缺少构建、宿主运行时不兼容、签名被拒或库查找失败都可能让应用在发出 driver 调用之前就停摆。TypeScript 方法签名可能不变但该消费者的安装与启动行为已经破坏。因此 SDK 必须保持实验状态直到完整平台与宿主矩阵全部加载成功包根刻意要求匹配的原生产物加载器失败被记录为文档化的包/运行时兼容性风险而不是隐式回退到被移除的 MCP facade。此外嵌入式/服务端 SDK 是全新的产品表面应按新产品版本化。把现有消费者从进程外 daemon 迁移到进程内引擎即使方法签名一致也可能是行为破坏权限身份、状态生命周期、崩溃隔离、并发与启动要求都变了。移除可执行 MCP 边界或改变这些行为属于另一项独立的破坏性变更。为什么直接引擎嵌入仍然需要设计工作UniFFI 只有在把 GUI 引擎移入 SDK 消费者进程时才可能移除 MCP。当前运行时不是为这种安排设计的。CLI 把工具执行路由到必需 daemon让策略、会话状态与 OS 集成只有一个所有者。macOS 上权限提示与授权挂接在运行中的 driver 身份上UI 工作依赖 daemon 的 run loopWindows 也有 daemon 与 UIAccess 进程问题部分授权与运行时配置在 daemon 生命周期内固定。相关启动与代理规则见 cli.rs。因此嵌入必须回答宿主身份、权限归属、全局状态、事件循环所有权、并发、崩溃恢复、多宿主应用共存。把当前 Rust 函数直接绑定过去并不会回答这些问题。关联文档的结论是把嵌入 driver 当作独立的产品架构配 OS 专项证明而不是一次客户端生成变更。仓库的 SDK 实现也遵循这一边界——embedded.rs 与embedded-host-uniffi-implementation-journal.mddocs/embedded-host-uniffi-implementation-journal.md记录的是嵌入式宿主设计工作而非把当前 daemon 拓扑悄悄替换成进程内引擎。成本与限制MCP 选择的可视代价关联文档明确列出 MCP 边界的成本并要求这些代价保持可见请求与结果跨 JSON 与进程边界Python 与 TypeScript 各自维护一小段传输实现SDK 必须管理代理启动、关闭、超时与协议版本协商稳定类型化方法与开放的 MCP 信封需要分别建模大尺寸截图走协议传输而不是进程内缓冲区。已实现的 UniFFI SDK 移除了语言原生 MCP 一跳但保留了 daemon 进程与 JSON socket 边界。其收益是实现与接口分发而非声称的截图吞吐提升。嵌入式/服务端 SDK 只有在上述运行时问题解决后才可能移除进程跳。决策不附带任何性能主张——没有可比的实现与基准就不作性能声明。另一个细节桌面成功结果仍是可扩展的协议信封而非封闭的 UniFFI 记录。其规范 Rust 校验器故意携带平台扩展映射而 UniFFI 无法把这些导出为任意serde_json::Value。因此 SDK 返回类型化的 text/image/error 元数据加structured_json与raw_json只有稳定的会话结果以专用记录跨 FFI 传递。把桌面结果改成封闭记录要么需要版本化稳定核心 扩展 JSON 字段要么是一次破坏平台数据保留的破坏性变更。为什么 Rust 与运行时仍然保持对齐契约即真相UniFFI 只是让语言绑定调用 Rust 定义接口的一种方式并不是防止契约漂移的唯一方式。cua-driver-contractcrate 把每个已发布工具绑定到类型化 Rust 输入与成功结构化输出。这些类型生成 manifest并通过编译后的 UniFFI SDK 导出。活动会话处理器直接消费同一批输入每个桌面后端在动作前先反序列化共享可移植投影活动注册表用同一批 Rust 输出类型校验成功结构化载荷CI 还证明每个可移植 schema 都被每个受支持 OS 的注册表接受见 cua-driver-contract/src/lib.rs 与 contract/README.md 的架构说明。这就在不生成第二份 Python/TypeScript MCP 契约层的前提下封死了契约与运行时的账本间隙。契约 crate 公开的常量进一步说明了单一事实来源的粒度TOOLS_LIST_SCHEMA_VERSION、CAPABILITY_VERSION、CONTRACT_VERSION当前0.7.0与MCP_PROTOCOL_VERSION2025-06-18都由 Rust 声明见 cua-driver-contract/src/lib.rs。已实现的生成与打包边界生成工具链PythonMozilla UniFFI0.31.0从编译后的cdylib元数据生成Node/TypeScript使用独立维护的uniffi-bindgen-react-nativeUBRN0.31.0-3N-API 目标外加锁定的ubjs/core检查入库的输出重新生成到临时根目录由所有权清单跟踪并在 CI 中逐字节比对。生成脚本是 generate-uniffi-bindings.mjs支持--check漂移模式。它按平台解析libcua_driver_sdk.dylib/cua_driver_sdk.dll/libcua_driver_sdk.so并对 TypeScript 输出做确定性后处理把相对 ESM 导入补上.js后缀、把ubjs/node运行时导入替换为仓库内的./node-runtime.js、把库选择器替换为resolveLibPath()——若预期的生成选择器发生变化生成直接失败而不是静默修补无关字符串。UBRN0.31.0-3有一个被显式测试记录的限制无法配置外部 UniFFI 组件从父 SDKcdylib加载符号。因此生成器执行一步带断言的后期处理让契约命名空间与 SDK 命名空间都加载libcua_driver_sdk。uniffi.toml 中cua_driver_contract外部包映射到cua_driver._native_contract见 cua-driver-sdk/uniffi.toml。打包与发布Pythonwheel 是平台相关的Rust release 工作流把匹配的 SDK 库放在每个 release 运行时归档中 CLI 旁wheel 构建器把库移到生成的 Python 模块旁CI 检查 wheel 并跨 FFI 边界运行它。包名为cua-driver当前版本0.20.0要求 Python3.10且运行时依赖为空原生实现全部经 FFI 进入见 python/pyproject.toml。Node公开包是单一平台中立的qwen-code/cua-sdk其 postinstall 选择匹配的 macOS / glibc Linux / Windows release 归档校验归档 checksum并缓存 SDK 库与 Node 运行时。Release CI 用原生 release 载荷冒烟测试安装后的 npm tarball且只在 GitHub Release 存在后才发布 npm。版本同步Python、npm 与 Rust 版本来自同一个 release tag。UniFFI 后续扩展的门禁关联文档要求对两个 SDK 目标Python 与 TypeScript分开评估。在把 UniFFI 路径扩展到新的运行时或平台之前必须在新增的 release OS 与架构上对原生产物做负载测试把目标归档加入原生解析与 release 矩阵在平台要求的所有位置保留原生库的 release 签名/公证证据让可执行 MCP 边界与导入 SDK 跑同一份 daemon 一致性语料库确保两条产品表面行为等价。嵌入式 SDK 则必须先有受支持的 Rust 持有宿主模型并文档化权限身份、端点所有权、generation 作用域生命周期、并发、父进程存活与恢复。MCP 保持 Agent 边界UniFFI 拥有应用侧生命周期与类型化调用。Python 与 TypeScript 必须独立评估绑定、加载器、打包工具链不同而无论任一 SDK 决策如何MCP 与 CLI 对 Agent 始终受支持。相关文档与进一步阅读决策文档why-cua-driver-uses-mcp-instead-of-uniffi.md评估与落地计划sdk-rust-source-of-truth-and-uniffi-evaluation-plan.md记录了 14 工具契约、A0 子集校验、语言分拆决策门禁与最终 2026-07-21 落地结果动作结果契约action-result-contract.md嵌入式宿主实现日志embedded-host-uniffi-implementation-journal.mdAgent 示例Claude / Codexnative 与 MCP 双路由examples/agent-sdks/README.md契约清单与生成物contract/README.mdSDK 核心实现cua-driver-sdk/src/lib.rs、cua-driver-contract/src/lib.rs、cli.rs结语Cua Driver 的集成选型最终可以压缩成一句话Agent 用 MCP 接入工具应用用 UniFFI 接入 Rust 实现两者正交共存。MCP 解决的是跨服务边界的工具调用UniFFI 解决的是一份 Rust 实现分发到 N 种语言移除其中任何一个都不会让另一个更有价值。这条边界让 Agent 集成保持零语言包依赖让应用 SDK 获得单一 Rust 事实来源的契约保障同时把进程内嵌入 GUI 引擎这种高风险形态明确划归未来的独立架构设计。对集成方而言判断自己属于哪条产品线Agent 消费者还是应用宿主就自然得到了正确的接入方式。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表