mcpField
A
agent-desktop-ffi

agent-desktop-ffi

github.com/vercel-labs开发16.8k202 次安装今天更新
代码仓库

关于 agent-desktop-ffi

agent-desktop-ffi 通过 C-ABI 提供 PlatformAdapter 操作接口,适用于希望从宿主程序调用桌面观察与交互的开发者,并支持引用操作、会话和结构化结果。

主要功能

  1. 01通过 C-ABI 调用适配器操作
  2. 02快照与基于引用的操作执行
  3. 03按会话保存引用映射
  4. 04精确定位与原生句柄
  5. 05结构化错误、追踪和等待

适用场景

  1. 01从 C 宿主程序调用桌面自动化
  2. 02使用限定引用构建观察-操作循环
  3. 03检查操作结果与错误详情

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/vercel-labs/agent-desktop --skill agent-desktop-ffi

安装后在 Claude Code 中输入/agent-desktop-ffi确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
build-and-link.md
error-handling.md
ownership.md
threading.md

详细介绍

agent-desktop-ffi

直接通过 C-ABI 访问 PlatformAdapter 操作。使用 release-ffi 配置构建 cdylib:

cargo build --profile release-ffi -p agent-desktop-ffi

输出文件为 target/release-ffi/libagent_desktop_ffi.dylib(Linux 上为 .so,Windows 上为 agent_desktop_ffi.dll),以及已提交的 C 头文件 crates/ffi/include/agent_desktop.h。默认的 release 配置使用 panic = "abort":如果 Rust panic 发生在 extern "C" 函数内,会对宿主进程触发 SIGABRT。release-ffi 保留 panic = "unwind",这是 panic 捕获所必需的。

以下四个参考主题按需加载:

  • ownership.md:谁分配、谁释放 FFI 返回的每个指针。
  • error-handling.md:errno 风格的 last-error 契约、错误代码、枚举验证、panic 边界。
  • threading.md:宿主线程契约、跨线程和进程的变更顺序、绑定适配器的原生句柄、AXIsProcessTrusted 的继承行为。
  • build-and-link.md:预构建归档、ABI 握手、结构体大小验证、C 和 Python 示例。

观察-操作工作流(规范路径)

ad_init(AD_ABI_VERSION_MAJOR)                    // verify header ↔ dylib match
adapter = ad_adapter_create_with_session("s1")   // or ad_adapter_create()
rc = ad_snapshot(adapter, "Finder", 0, 10, false, false, &json_out)
// parse json_out: locate snapshot-qualified refs in data.tree
ad_free_string(json_out)
// build action:
AdAction act = {0}; act.kind = AD_ACTION_KIND_CLICK;
rc = ad_execute_by_ref(adapter, "@s8f3k2p9:e5", &act, 0, &result_out)
ad_free_string(result_out)
ad_adapter_destroy(adapter)

ad_snapshot 返回 CLI 信封 {version, ok, command, data}。data.tree 包含带快照标识的交互元素引用。信任树之前,请先读取 data.complete:false 表示观察预算已耗尽,树是不完整的,并非错误。ad_snapshot 始终以 app 的焦点窗口为目标;ABI 不提供窗口目标选择、骨架模式和 --root 下钻功能。裸 @eN 引用会返回 AD_RESULT_ERR_INVALID_ARGS。

核心约束

  • ABI 握手。 加载库后调用一次 ad_init(AD_ABI_VERSION_MAJOR)。版本不匹配时会返回 AD_RESULT_ERR_INVALID_ARGS:应中止。ad_abi_version() 返回库的主版本号以供显示。删除符号或更改布局时,主版本号会递增;新增 ad_* 符号和错误代码则是增量兼容的。请固定链接所用的 libagent_desktop_ffi 确切版本。

  • 会话适配器。 ad_adapter_create_with_session("session-id") 会将引用映射表持久化范围限定在会话命名空间中,类似 CLI --session <id>。ID 长度为 1 到 64 个 ASCII 字母数字字符、- 或 _。空 ID 的行为与 ad_adapter_create() 相同。ID 无效时返回 null(读取 ad_last_error_*)。

  • 引用操作。 ad_execute_by_ref 是主要的操作入口。它会加载 RefStore,严格解析引用(快照中没有该引用或元素已更改时返回 STALE_REF;存在多个候选项时返回 AMBIGUOUS_TARGET),执行实时可操作性预检(可见、稳定、已启用、支持的操作、策略、可编辑),然后分发操作。目标已禁用或不支持时,会在任何平台调用发生前失败;返回 AD_RESULT_ERR_ACTION_FAILED 时,检查报告为 ad_last_error_details() 中的 JSON。它会在预检前自动等待 5000 ms;ad_execute_by_ref_timeout 接受 timeout_ms(-1 = 默认 5000 ms,0 = 单次尝试)。PressKey 默认使用 focus_fallback;其他所有操作(包括 TypeText)默认使用 headless。传入 AD_POLICY_KIND_FOCUS_FALLBACK(1)可允许在不移动光标的情况下聚焦;传入 AD_POLICY_KIND_HEADED(2)可允许通过物理光标和键盘发送操作。ad_execute_ref_action_exact_with_policy 会对 AdExactRefEntry 执行相同的预检。

  • 具备进程代际安全性的直接 API。 每个直接定位函数都需要进程代际凭据:AdExactRefEntry、AdExactWindowInfo、ad_list_windows_exact、ad_launch_app_exact 及其他 *_exact 符号。AdRefEntry、AdWindowInfo 和 AdSurfaceInfo 仅作为字段嵌入精确结构体中。ad_list_surfaces_exact 会保留 surface id。从 AD_EXACT_SURFACE_INFO_VERSION 2 开始,AdExactSurfaceInfo.unclassified 会列出探测器无法读取的 surface 类型(例如 sheet,menu),或者为 null。如果已列出某种类型,但没有 sheet 或 menu,则表示未知,而非不存在。只有 Windows 适配器会填充此字段;macOS 和 Linux 返回 null。

  • 原生句柄。 ad_resolve_element_exact 和 ad_find_exact 会返回一个 AdNativeHandle。ad_execute_action(无头模式,不进行预检)和 ad_execute_action_with_policy 会直接对其操作,绕过 ref-action 流程。在所有平台上,都必须在调用 ad_adapter_destroy 之前,于同一适配器和线程上通过 ad_free_handle(adapter, &handle) 释放每个句柄。该函数会将 handle.ptr 置零,因此再次调用不会执行任何操作。

  • 操作结果。 AdActionResult.steps 会映射激活链操作的 CLI steps 数组。每个 AdActionStep 都有 label 和 outcome 字符串、mechanism(AD_STEP_MECHANISM_SEMANTIC_API = 1 或 AD_STEP_MECHANISM_PHYSICAL_SYNTHETIC = 2,仅当 has_mechanism 为真时有效),以及 verified(仅当 has_verified 为真时有效)。AdActionResult.disposition 包含与 ad_last_error_delivery_semantics 相同的交付/重试组合。通过 ad_free_action_result(&out) 释放结果。

  • 显示器发现。 使用 AdScreenshotTarget.screen_index 之前,请先调用 ad_list_displays。列表顺序即截图索引顺序。每个 AdDisplayInfo 都包含稳定的显示器 ID、边界、主显示器标记和缩放比例。通过 ad_display_list_free 释放列表。

  • 错误。 调用失败时会设置线程局部的最后错误状态;在下一次失败调用之前,通过 ad_last_error_* 访问器读取该状态。ad_last_error_details() 会返回结构化 JSON(ACTION_FAILED 时为可操作性报告,AMBIGUOUS_TARGET 时为候选项摘要),其中可能包含用户屏幕上的元素名称、值和窗口标题:请勿将其写入共享日志。ad_last_error_delivery_semantics 会报告失败的操作是否已交付,以及重试是否安全。无效枚举判别值会返回 AD_RESULT_ERR_INVALID_ARGS。请参阅 error-handling.md。

  • 线程处理。 入口点可从任意宿主线程调用。原生句柄必须留在创建它们的适配器和线程上;跨线程传递经过限定的 ref。桌面变更操作会获取与 CLI 相同的跨进程交互租约;读取操作无需租约,并带有有限期限。读/读、读/变更和变更/变更矩阵请参阅 threading.md。

  • 跟踪。 文件跟踪(与 CLI --trace 使用相同的 JSONL 格式;片段包含 event、ts_ms、seq 和已脱敏字段)仅在会话具有 trace: on 的清单时启用。该清单必须由 session start 创建(或等效清单已存在于磁盘上),且必须在创建适配器之前创建。单独调用 ad_adapter_create_with_session 不会写入任何内容。每个 OS 进程都会追加到一个片段:~/.agent-desktop/sessions/<id>/trace/<pid>-<procTs>.jsonl;长期运行的宿主会重复使用该片段。ad_trace_show(JSON 信封)和 ad_trace_export(独立 HTML 文件)会读取适配器会话的合并时间线;limit -1 = CLI 默认值。

  • 日志回调。 ad_set_log_callback(cb) 会注册一个进程级回调,用于接收诊断信息,与会话清单无关。它会以 JSON 形式接收同一线程上后续 ad_* 调用中发出的 tracing 事件;FFI 不会安装或替换宿主进程的全局 tracing 订阅器。cb 接收一个 int32_t 级别(1=ERROR ... 5=TRACE)和一个仅在调用期间有效的 const char *msg。传入 NULL 可取消注册。敏感字段值(密码、令牌、文本等)会替换为 {"redacted":true}。回调不得跨越 C ABI 展开:请在回调内部捕获 C++ 异常和 Rust panic,因为违规可能导致宿主进程中止。回调可能同时从多个宿主线程触发,也可能在传入 NULL 取消注册后短暂触发:请确保回调及其捕获的任何数据在进程生命周期内始终有效。

  • 等待。 ad_wait(adapter, args, &out) 会运行 CLI wait 命令。设置 mode.pause(AdOptionalU64,毫秒)、mode.element、mode.window(等待标题匹配的窗口)、mode.text,或设置 mode.surfaces.menu、.menu_closed、.notification 之一;添加 predicate 组(predicate、value、action、count),以及 scope.timeout_ms / scope.app。CLI 事件等待(--event、--window-id)未开放。请将 AdWaitArgs 零初始化,并在调用前根据 AD_WAIT_ARGS_SIZE / ad_wait_args_size() 验证结构体大小。输出是一个 {version, ok, command, data} 信封,使用 ad_free_string 释放。ad_wait 会阻塞调用线程,最长等待 scope.timeout_ms 毫秒。并发调用 ad_adapter_destroy 不会使正在执行的等待失效。

  • 文本输入隐私。 在 macOS 上,焦点回退或有头模式下的文本插入可能会短暂使用剪贴板处理非 ASCII 文本。对于敏感文本,如果目标支持可设置值,请优先使用 AD_ACTION_KIND_SET_VALUE 和 AD_POLICY_KIND_HEADLESS。

  • ad_get_tree_exact 与 ad_snapshot 的区别。 ad_get_tree_exact 返回原始扁平广度优先树:不含 refs、不持久化 refmap,也没有 JSON 信封(使用 ad_free_tree 释放)。可用于自定义遍历或 UI 检查。对于通过 ad_execute_by_ref 执行动作的观察-行动 Agent,请从 ad_snapshot 开始。

评论

支持 Markdown