ARTICLE DETAIL

资讯详情

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

qwen-code 中 Cua Driver 的动作结果契约与后置条件校验:ActionResult / VerifyStateOutput 深度指南

qwen-code 中 Cua Driver 的动作结果契约与后置条件校验:ActionResult / VerifyStateOutput 深度指南 qwen-code 中 Cua Driver 的动作结果契约与后置条件校验ActionResult / VerifyStateOutput 深度指南【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读本文以 packages/cua-driver/docs/action-result-contract.md 为骨架系统讲解 Cua Driver 0.15 起引入的「动作结果Action Result」与「后置条件校验Postcondition Verification」双契约设计ActionResult只回答驱动端动作执行事实VerifyStateOutput只回答调用方自定义后置条件是否成立两者职责彻底分离。读完本文你将掌握动作结果五档效果值的语义与不变式、窗口目标解析规则、verify_state三态校验协议、Python/TypeScript/Rust SDK 的取值方式、升级动作阶梯的决策模型以及从 0.14 迁移到 0.15 的全部注意事项。一、背景0.15 为何要把「动作事实」与「任务含义」分离Cua Driver 0.15 把早期版本混在一起的两种事实拆开这是本文一切内容的设计原点ActionResult描述驱动端执行动作时走了哪条路由route、能对动作本身负责到什么程度effect。它回答的是「动作发出去了吗驱动能否证明其效果」。VerifyStateOutput描述调用方预先定义的后置条件postcondition当前是satisfied、unsatisfied还是unknown。它回答的是「调用方关心的目标状态达成没有」。从源码看这一分工被落实为两个独立的 Rust 契约类型ActionResult定义于 outputs.rsVerifyStateOutput定义于 verification.rs。verification.rs模块文档写得很明确The caller owns the task-level meaning of success. The driver only checks bounded predicates against one explicitly authorized window.任务层面的成功含义归调用方所有驱动端只对一个显式授权的窗口检查有界谓词。驱动端报告这些事实而 Agent harness如 qwen-code 的调用方负责任务含义、视觉读取、停止/重试决策以及在动作阶梯action ladder上的推进。动作阶梯即文末 escalation 机制描述的多级路由升级路径。二、MCP 动作结果ActionResult契约详解2.1 成功响应的封闭式 structuredContent每次成功的动作调用都会返回一个**封闭closed**的structuredContent对象即不允许出现契约之外的字段{ effect: confirmed, route: accessibility, delivery: {mode: background}, evidence: [{kind: value_readback}] }其中effect与route是必填字段。所谓「封闭」在实现上由#[serde(deny_unknown_fields)]与output_schema_with_additional_properties::Self(false)双重保证见 outputs.rs。契约的生成物可在 contract/manifest.json 中直接查看以click工具为例其success_output_schema声明了effect、route必填delivery/evidence/escalation可空且additionalProperties: false。2.2 字段取值全表字段取值effectconfirmed、partial、unverifiable、suspected_noop、refusedrouteaccessibility、synthetic_events、global_input、dom、trusted_inputdelivery.modebackground、foreground、not_applicable、unknownevidence[].kindvalue_readback、window_changeescalation.targetpixel、foreground、page、sessionescalation.reasonroute_unavailable、delivery_failed、effect_unconfirmed、suspected_noop、permission_required对应到源码ActionEffect枚举见 outputs.rsPython SDK 侧的同名枚举生成于 _native_contract.pyActionRoute枚举见 outputs.rs注意契约文档表格中列出 5 种而当前仓库 manifest 与 Rust 源码中已扩展为 6 种新增了system_api系统 API 路由ActionDeliveryMode四种 delivery 模式见 outputs.rsActionEvidenceKind两种证据类型见 outputs.rsActionEscalationTarget/ActionEscalationReason见 outputs.rs。2.3 使用 ActionResult 契约的动作工具清单以下工具统一走该动作结果契约click、double_click、right_click、scroll、drag、mouse_drag、parallel_mouse_drag、move_cursor、mouse_button_down、mouse_button_up、type_text、type_text_chars、press_key、hotkey、set_value、set_window_frame、invoke_menu、browser_click、browser_pointer、browser_type。其他变更类工具——如应用启动、窗口激活、浏览器导航、对话框、上传、下载——保留各自独立的类型化结果不套用ActionResult。2.4 契约是「封闭」的不回声请求字段该契约刻意保持封闭不回声以下内容选择器selector、坐标coordinates、作用域scope、目标target、平台传输名platform transport names、诊断指针diagnostic pointers以及旧版的verified布尔字段。原因在于这些信息要么是请求上下文调用方自己保留即可要么是内部诊断不应暴露到公共契约。测试用例action_result_round_trips_without_legacy_or_request_fields专门验证了这一点向合法结果中插入scope、target、x、y、path、transport、verified、extensions中任意一个字段反序列化都会失败见 outputs.rs。2.5 三条核心不变式契约在实现层强制校验三条不变式由ActionResult::validate_invariants()保证outputs.rs并有对应测试action_result_enforces_effect_invariantsconfirmed必须携带可发布的读回readback或窗口变化window-change证据——即evidence非空否则报confirmed effect requires evidencepartial必须携带delivery.delivered_count——即投递计数用于表达「部分送达」refused既不能有 delivery 也不能有 evidence——被拒绝的动作没有投递行为也没有效果证据。为什么confirmed要求这么严看驱动内部的动作记录 action_record.rseffect_from_value_readback(confirmed, changed, readback_available)中只有confirmed readback_available有独立的值读回作为确认依据才归为Confirmed读回不可用或值已变化归为Unverifiable读回可用但值未变化则是更强的「无操作」信号归为SuspectedNoop。也就是说驱动绝不会仅凭「事件发出去了」就宣布 confirmed。三、窗口目标解析PID 唯一化与歧义拒绝窗口作用域的动作window-scoped actions允许「只给 PID、不给window_id」但仅在该进程恰好只有一个符合条件的顶层窗口时成立。此时驱动会先把该唯一匹配提升为精确的(pid, window_id)目标再执行派发。需要特别注意的失败分支PID 拥有多个符合条件的窗口动作在发送任何输入之前就失败返回code: ambiguous_window_target、effect: refused并附带一个candidates数组其中每个候选包含window_id、标题、应用名可用时、屏幕可见状态。正确的处理方式是调用list_windows({pid})挑出目标窗口然后携带显式window_id重试。PID 没有任何符合条件的窗口失败码为code: window_target_not_found。显式window_id目标与element_token目标保持原有的精确解析语义上述守卫不会替换或重新解释它们。此外文档强调一个动作虽然到达了执行器actuator但缺少可信读回只能算unverifiable绝不能升级为confirmed。截图变化、原生 API 接受、事件接收、操作者观察这些都可能是有用的内部诊断但不足以独立支撑confirmed结论。四、后置条件校验verify_state 三态协议动作执行之后用verify_state做有界的结构化后置条件校验contract 契约见 verification.rssatisfied唯一的成功终态。只有它才允许 harness 判定任务子步骤完成。unsatisfied可以成为重试或切换动作阶梯路由的理由。unknown现有观测既不能证明成立也不能证明不成立绝不能被提升为成功。4.1 校验输入与输出VerifyStateInputverification.rs的关键参数参数说明约束/默认值pid可被观测的精确进程正整数window_id精确的原生窗口标识整数expect1~8 个谓词逻辑 AND 组合minItems1, maxItems8timeout_ms有界等待0 表示单次采样0~10000默认 5000stable_samples要求连续稳定满足的采样数1~5默认 2include_screenshot是否附带最终窗口截图布尔谓词支持两类窗口级exists、boundsbounds 可带tolerance_px与元素级selector用role/label_contains匹配可断言exists、value_equals、enabled、selected。注意元素exists: false是被直接拒绝的true_only_boolean_schema强制只能传true因为元素遍历在某些平台上尚不保证穷尽无法证明「不存在」与其返回永久的unknown不如显式拒绝。VerifyStateOutputverification.rs返回status三态、stable是否连续稳定、elapsed_ms、samples、predicates[]每个谓词的index、status、unknown_reason、observed_json。unknown的细分原因枚举UnknownReason包括invalid_predicate、unsupported_predicate、untrusted_source、multi_match、target_missing、observation_unavailable、stability_unproven。4.2 include_screenshot 是「未解释证据」开启include_screenshot后返回的截图属于未解释的视觉证据uninterpreted evidence。Cua Driver 自身不做 OCR、也不为截图赋予任务含义契约 README 也明确Cua Driver does not OCR or assign task meaning to it见 contract/README.md。是否停止、重试或继续前进由多模态 harness 读取截图后自行决策——这正是「任务含义归 harness」原则的体现。五、SDK 访问Python / TypeScript / Rust 三端取值Rust、Python、TypeScript 三个 SDK 都保留传输无关的ToolResult信封envelope包含text、images、structured JSON、错误状态/错误码、降级状态degraded state、原始 JSON。歧义的verified字段已被移除。成功的动作调用类型化值在result.actionRust 中为借用访问器result.action()。成功的verify_state调用类型化值在result.verificationRust 中为result.verification()。Python 示例result await driver.click(click_input) if result.action.effect is ActionEffect.CONFIRMED: verification await driver.verify_state(expectation) if verification.verification.status is VerificationStatus.SATISFIED: return doneTypeScript 示例const result await driver.click(input) if (result.action?.effect ActionEffect.Confirmed) { const checked await driver.verifyState(expectation) if (checked.verification?.status VerificationStatus.Satisfied) { return done } }这两个代码片段组成了 0.15 之后的标准动作闭环范式先确认动作效果confirmed再校验后置条件satisfied两者都通过才算该步骤完成。Python 侧的ActionEffect、VerificationStatus枚举由 UniFFI 从 Rust 契约生成见 _native_contract.py测试test_uniffi_loader.py中也有action_result.action.effect is ActionEffect.UNVERIFIABLE的断言示例test_uniffi_loader.py。六、升级Escalation属于 harness建议而非自动重试escalation字段是可选的它只是建议adviceharness 收到后不一定要自动重试。各目标对应的建议行动目标targetharness 建议行动pixel刷新视觉状态选取精确的像素目标foreground会话策略允许时显式选择前台投递page将原生窗口绑定到受支持的浏览器页面路由session仅当策略允许时准备或显式拓宽会话四种 escalation 原因route_unavailable、delivery_failed、effect_unconfirmed、suspected_noop、permission_required对应动作阶梯中不同的升级动机路由不可用 → 换更高层级路由投递失败 → 换投递模式效果未确认 → 需要更可靠的回读路径疑似无操作 → 换目标或换机制权限不足 → 需要会话/权限升级。设计上这条「窄事实契约」之上可以有多种策略实现SDK 集成方、OpenClaw、Hermes 等不同 agent host 可以各自实现不同的升级策略而无需复制各平台执行器actuator的细节。这保证了事实层与策略层解耦。七、从 0.14 迁移到 0.15升级到 0.15 时按以下清单逐项调整用result.action.effect取代result.verified检查——动作事实只从 effect 读取result.verification.status只用于verify_state的后置条件——不要把动作效果与校验状态混用替换已删除的类型ClickOutput、DesktopActionOutput、MoveCursorOutput一律改为ActionResult不要从动作响应中读取坐标、scope、path、transport或请求目标——这些是请求上下文需要时在调用方自己保留move_cursor不再回声x/y——需要观察指针位置时改调get_cursor_position把unverifiable当作未知动作效果——既不是失败也不是成功MCPisError只代表传输/工具级失败——成功响应中的ActionResult需要单独审视daemon 与 SDK 必须一起升级——0.15 SDK 对遗留的 0.14 动作载荷采取「显式拒绝」而非「猜测其含义」避免歧义传播。其中第 4 条的封闭性、第 7 条对isError的处理都与 outputs.rs 中advertised_output_schema的设计呼应MCP 要求所有structuredContent都通过广告的outputSchema校验若只广告成功形状严格客户端会把拒绝载荷直接判为 schema 校验错误从而丢失「element_token 已过期请重新调用 get_window_state」这类可操作信息因此实际广告的 schema 是「成功形状 拒绝信封」的联合anyOf成功变体保持封闭严格校验拒绝信封作为姊妹变体共存。八、契约的生成与验证工程实践该契约以 Rust cratecua-driver-contract为单一事实来源source of truth由cua-contract-gen生成 manifestcontract/manifest.json以及 Python/TypeScript 的 UniFFI 绑定。相关验证命令在packages/cua-driver/rust下执行cargo run -p cua-driver-contract --bin cua-contract-gen -- all cargo run -p cua-driver-contract --bin cua-contract-gen -- all --check cargo test -p cua-driver-contract cargo test -p cua-driver-core --test contract_parity cargo test -p cua-driver --test schema_consistency_test \ portable_desktop_contracts_are_accepted_by_active_backendSDK 加载器测试位于 test_uniffi_loader.py 与typescript/test/native-loader.test.mjs。CI 会检查 manifest 生成器、确定性再生成两套 UniFFI 绑定、与活动工具注册表比对一致性并把真实 Python/Node FFI 加载器接入确定性 daemon-socket fixture 进行交叉验证详见 contract/README.md。契约版本管理在边界处分别追踪contract_version0.7.0生成 manifest 与类型化 SDK 形状、tools_list_schema_version1、capability_version1能力令牌词汇表为增量扩展、mcp_protocol_version2025-06-18MCP 初始化协议。结语Cua Driver 0.15 的动作结果契约是一次清晰的职责切分驱动负责「事实」harness 负责「意义」。ActionResult用五档 effect 值诚实表达驱动对动作的掌控程度用封闭 schema 杜绝请求字段与内部诊断泄漏VerifyStateOutput用三态结果把「后置条件是否成立」这一任务层判断交还给调用方。理解并遵守这两套契约是正确构建基于 Cua Driver 的桌面自动化 Agent 的基础——无论你是直接使用 MCP 工具面还是通过 Python/TypeScript/Rust SDK 集成。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表