关于 agent-desktop-ffi
agent-desktop-ffi 通过 C-ABI 提供 PlatformAdapter 操作接口,适用于希望从宿主程序调用桌面观察与交互的开发者,并支持引用操作、会话和结构化结果。
主要功能
- 01通过 C-ABI 调用适配器操作
- 02快照与基于引用的操作执行
- 03按会话保存引用映射
- 04精确定位与原生句柄
- 05结构化错误、追踪和等待
适用场景
- 01从 C 宿主程序调用桌面自动化
- 02使用限定引用构建观察-操作循环
- 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.mderror-handling.mdownership.mdthreading.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会保留 surfaceid。从AD_EXACT_SURFACE_INFO_VERSION2 开始,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会映射激活链操作的 CLIsteps数组。每个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)会运行 CLIwait命令。设置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开始。