• 简体中文
  • Computer Use

    computer-use 是一个为驱动真实桌面而设计的 worker 进程:

    • 鼠标和键盘
    • 截图
    • 剪贴板
    • 窗口列表
    • 无障碍树(accessibility tree)

    它是独立于 aiod 的进程,可以运行在任何有桌面的主机上。例如:

    • 一台 Ubuntu 桌面
    • 一台跑 Xvfb 或 Xvnc 的虚拟机
    • 一台带交互登录会话的 Windows 主机

    aiod 只代理它的 API,不直接接触桌面。这层进程边界让桌面能力成为可选项:没有桌面时 aiod 照常运行,有桌面时则通过 computer-use 触达它。

    桌面能力只在 v2 提供,路径在 /v2/computer/* 下。

    v1 为 1.x 客户端保留两个别名:

    • POST /v1/browser/actions
    • POST /v1/display/record

    路由对照见 从 1.x 迁移

    这一页前半部分介绍 agent 工具使用的动作,后半部分介绍用于观察或接管同一个桌面的查看器。

    基于 CDP 的页面自动化见 浏览器 API;完整的桌面任务演示见 Computer Use 示例

    面向 agent 的工具

    连接 daemon 与 worker

    worker 监听 AIO_COMPUTER_USE_LISTEN(默认 0.0.0.0:18100)。aiod 通过 AIO_COMPUTER_USE_URL(默认 http://127.0.0.1:18100)连接 worker,并代理桌面路由。

    worker 停止时,这些路由返回 503

    {
      "success": false,
      "message": "computer-use worker is not available",
      "data": null,
      "hint": "start computer-use or set AIO_COMPUTER_USE_URL"
    }

    两个 v1 别名走的是同一个 worker,返回同样的结果。

    运行 worker 的条件

    Linux:需要一个可达的 X11 display。设置 DISPLAY;如果该 display 需要 cookie 鉴权,再设置 XAUTHORITYGET /v2/computer/info 会返回探测到的 displayxauthority

    Windows:一个交互登录会话。aiod 自己可以作为 Session 0 的 SCM 服务运行。

    computer-use 必须运行在交互登录会话中,才能看到桌面并注入输入。

    查看当前可用能力

    GET /v2/computer/info 返回 worker 探测到的 display,以及该 display 支持的能力:

    curl "$BASE_URL/v2/computer/info"

    data 是:

    • available —— worker 是否连上了 display
    • display —— worker 找到的 display
    • xauthority —— worker 找到的 XAUTHORITY
    • screen_resolution —— {width, height}
    • capabilities —— {screenshot, actions, clipboard, recording}
    • warnings —— 探测过程中发现的问题

    v1 没有桌面 info 路由。该 plane 的状态由沙箱能力探测报告:

    curl "$BASE_URL/v1/capabilities"

    data.computer 是:

    • status —— readydegradedabsent
    • displayresolution —— worker 找到的显示环境
    • screenshotactionsclipboardrecordingaccessibility —— 每项操作一个标志位
    • accessibility_backend —— atspiuia,没有编译进后端时是 null
    • providermissingwarnings —— 能力来源,以及缺少的内容

    worker 未运行时,响应如下:

    {
      "status": "absent",
      "provider": null,
      "display": null,
      "screenshot": false,
      "actions": false,
      "clipboard": false,
      "recording": false,
      "accessibility": false,
      "accessibility_backend": null,
      "resolution": {
        "width": null,
        "height": null
      },
      "missing": [
        "computer-use"
      ],
      "warnings": [
        "computer-use worker probe failed: error sending request for url (http://127.0.0.1:18100/capabilities)"
      ]
    }

    需要worker 的可用性和它找到的 XAUTHORITY 时,切到 v2:

    截图

    响应体就是图片本身:

    curl "$BASE_URL/v2/computer/screenshot" -o desktop.png

    截取的是整个桌面的 PNG:所有窗口、任务栏、对话框。响应头带上尺寸 —— x-image-widthx-image-heightx-screen-widthx-screen-height

    v1 没有单独的桌面截图路由。使用动作接口返回的截图;如果只想截图,可以发送不改变桌面状态的 WAIT 动作:

    curl -X POST "$BASE_URL/v1/browser/actions?include_screenshot=true" \
      -H "Content-Type: application/json" \
      -d '{"action_type": "WAIT", "duration": 0.5}'

    响应里的 screenshot 是桌面截图,格式为 base64 PNG。

    Python SDK 不会为该路由附加查询参数,因此需要直接发 HTTP 请求。GET /v1/browser/screenshot 截取的是浏览器页面,不是整个桌面。

    需要不附带动作、直接取到 PNG 响应体时,切到 v2:

    执行动作

    一次请求一个动作,坐标是屏幕坐标。加 ?include_screenshot=true 把观察步并入动作步:

    curl -X POST "$BASE_URL/v2/computer/actions" \
      -H "Content-Type: application/json" \
      -d '{"action_type": "CLICK", "x": 640, "y": 400}'
    
    curl -X POST "$BASE_URL/v2/computer/actions?include_screenshot=true" \
      -H "Content-Type: application/json" \
      -d '{"action_type": "SCROLL", "dx": 0, "dy": -3}'
    curl -X POST "$BASE_URL/v1/browser/actions" \
      -H "Content-Type: application/json" \
      -d '{"action_type": "CLICK", "x": 640, "y": 400}'
    
    curl -X POST "$BASE_URL/v1/browser/actions?include_screenshot=true" \
      -H "Content-Type: application/json" \
      -d '{"action_type": "SCROLL", "dx": 0, "dy": -3}'

    别名和 v2 路由是同一个 handler:请求体相同,响应相同。

    Python SDK 一次发一个带类型的动作:

    Python
    TypeScript
    from agent_sandbox import Sandbox
    from agent_sandbox.browser.types.action import Action_Click
    
    client = Sandbox(base_url="http://127.0.0.1:18091")
    client.browser.execute_action(request=Action_Click(x=640, y=400))

    它的动作联合类型覆盖鼠标、键盘和 WAIT。下面列出的剪贴板、窗口和节点动作要在同一个路由上走 HTTP,动作后截图也一样。

    v1 和 v2 的动作请求体相同,例如点击屏幕坐标 (640, 400)

    {
      "action_type": "CLICK",
      "x": 640,
      "y": 400
    }

    请求体直接描述动作,action_type 决定具体执行哪一种:

    action_type必需参数可选参数
    MOVE_TOxy——
    MOVE_RELx_offsety_offset——
    CLICK——xybuttonnum_clicks
    RIGHT_CLICK——xy
    DOUBLE_CLICK——xy
    MOUSE_DOWN——button
    MOUSE_UP——button
    DRAG_TOxy——
    DRAG_RELx_offsety_offset——
    SCROLL——dxdy
    TYPINGtextuse_clipboard
    PRESSkey——
    KEY_DOWNkey——
    KEY_UPkey——
    HOTKEYkeys——
    WAITduration——
    SET_CLIPBOARDtext——
    WINDOW_ACTIVATEwindow_id——
    WINDOW_MINIMIZEwindow_id——
    NODE_FOCUSnode_id——
    NODE_INVOKEnode_idaction
    NODE_SET_VALUEnode_idvalue——
    • duration 的单位是秒;keys 是一个列表,复制是 ["ctrl", "c"]
    • window_id 来自窗口列表,node_id 来自无障碍树,两者都在下文。
    • 有两条限制对每个动作都成立,单发和批量都一样:单个 WAIT 最多 10 秒,单个 SCROLL 每个方向最多 100 格。
    • TYPING 对 ASCII 文本直接按键输入;含其他字符的文本走剪贴板(use_clipboard,默认 true),会覆盖剪贴板原有内容;use_clipboard: false 时这类文本返回 400,因为按键输入会丢字。剪贴板里的文本用 Shift+Insert 粘贴,终端和 GTK、Chromium 窗口都接受这个组合键。
    • PRESSHOTKEYTYPING 成功只表示输入已送到焦点窗口,不表示应用已经响应。用截图确认结果。
    • 每种类型的完整 schema 见 API 参考

    响应包含 statusaction_performed。请求动作后的截图时,响应还会包含 base64 PNG。

    如果截图失败,响应会在动作结果旁返回 screenshot_error,但不会让整个请求失败;动作本身已经执行。

    批量动作

    一次请求按顺序执行一批动作。在执行期间,其他调用不能操作桌面:

    curl -X POST "$BASE_URL/v2/computer/actions/batch" \
      -H "Content-Type: application/json" \
      -d '{"include_screenshot": true,
           "actions": [
             {"action_type": "HOTKEY", "keys": ["ctrl", "l"]},
             {"action_type": "TYPING", "text": "example.com"},
             {"action_type": "PRESS", "key": "enter"}
           ]}'

    该路由中的 include_screenshot 是 body 字段,不是查询参数。

    每批最多包含 50 个动作,所有 WAIT 的总时长最多为 20 秒。

    data 是:

    • performed —— 已执行的动作,按顺序
    • failed_indexerror —— 哪个动作中断了这批,以及原因;它之前的都执行了
    • statusreason —— 主机拒绝输入时是 denied 和机器可读的原因
    • screenshotscreenshot_error —— 最后一个执行到的动作之后的那一帧

    别名一次只接一个动作。一串动作就是同样多次往返,中间可能被别的调用挪动指针。

    需要一串动作中间不被其他调用插入时,切到 v2:

    自己写自动化脚本

    桌面就是一个普通的 X display,每条命令都带着 DISPLAY,所以直接操作屏幕的脚本可以通过 POST /v2/commands(v1 为 /v1/bash/exec)跑在上面这些动作所用的同一个桌面上。Computer 镜像自带 xdotool;pyautogui 用 pip install pyautogui 装一次即可:

    sb = Aio(BASE_URL)  # 示例首页定义的 helper
    sb.post("/v2/commands", command="pip install --quiet pyautogui", timeout=280)
    sb.post("/v2/commands", command='''python3 - <<'EOF'
    import pyautogui
    pyautogui.moveTo(320, 240)
    pyautogui.click()
    pyautogui.write("hello")
    pyautogui.screenshot("/tmp/desk.png")
    EOF''')
    print(sb.get("/v2/computer/cursor"))   # {'x': 320, 'y': 240}

    读取指针、剪贴板、窗口列表

    端点作用说明
    GET /v2/computer/cursor当前指针位置屏幕坐标
    GET /v2/computer/clipboard读取剪贴板文本读取超时 5 秒,大小上限 1 MiB
    GET /v2/computer/windows列出顶层窗口xdotool 路径下最多 200 个

    窗口列表的结构是 {snapshot_id, windows: [{window_id, title, process_id, bounds, minimized}]}

    window_id 是原生窗口句柄,不是列表序号。只要窗口仍然存在,它就一直有效;对已关闭窗口的操作会失败,不会误操作后来复用同一位置的窗口。

    这三个在 v1 都没有路由。写剪贴板是一个动作,SET_CLIPBOARD 可以走别名;但无法读取剪贴板内容。

    需要窗口列表、指针位置或剪贴板文本时,切到 v2:

    通过无障碍树操作

    桌面无障碍树有两个路由:

    • GET /v2/computer/accessibility:返回整棵无障碍树。
    • GET /v2/computer/accessibility/nodes:在整棵树上执行扁平搜索。

    两个路由都支持 ?role=button&name=Sign+in 等查询参数,并接受同一组字段:

    字段取值含义
    scopeforeground(默认)、desktop只看活动窗口,还是走遍所有顶层窗口
    rolenamestring只保留匹配的部分
    matchsubstring(默认)、exactregexrolename 的比较方式
    states逗号分隔节点必须同时具备的状态(enabled,showing
    include_offscreenboolean,默认关包含后端标记为屏幕外的节点
    max_depth1–64,默认 32深度预算
    max_nodes1–20000,默认 5000节点数预算
    timeout_ms100–60000,默认 5000遍历的墙钟预算
    limit1–1000,默认 50nodes:最多返回多少节点

    超出范围的值会被限制在允许的区间内,不会被拒绝。rolename 在所有匹配模式下都不区分大小写。

    truncated 表示结果达到上限,因此没有找到某个节点并不代表它不存在。只有 nodes 支持 ?node_id=;传入后会解析单个句柄,并忽略其他搜索参数。

    返回的 node_id 在元素存在期间有效,跨快照也有效。窗口关闭或所属应用重启后,元素会消失,再使用该 id 会返回 404

    node_id 传给 NODE_FOCUSNODE_INVOKENODE_SET_VALUE,即可按元素操作,无需使用像素坐标。

    别名接受 NODE_* 动作,但这些动作需要的句柄来自两个 v2 无障碍树路由。v1 没有这两个路由,因此无法获取句柄。

    需要按 role 和 name 定位元素、而不是用像素坐标操作时,切到 v2:

    后端按平台提供:Linux 使用 AT-SPI2(Assistive Technology Service Provider Interface,辅助技术服务提供接口),Windows 使用 UI Automation(UIA)。

    501 表示平台没有可用的后端,例如平台尚未实现,或 Linux 镜像缺少 AT-SPI 运行时。重试不会改变结果。

    503 表示后端存在,但当前无法读取,例如没有交互桌面或没有获得焦点的窗口。Chromium/Electron 应用必须使用 --force-renderer-accessibility 启动,才会暴露无障碍树。

    录屏

    POST /v2/computer/record 负责开始、查询和停止录制:actionstartstatusstop

    POST /v1/display/record 提供同样的能力:actionstartstatusstop。Python SDK 支持该路由的全部参数:

    Python
    TypeScript
    client.display.record(action="start", save_path="/workspace/recordings/session.mp4")
    client.display.record(action="stop")

    录制基于 ffmpeg,同一时间只能有一个在跑。start 接受这些采集参数:

    参数范围默认值
    fps1–6030
    crf0–51(越低画质越好)30
    max_duration最长 600 秒60
    widthheight像素探测到的屏幕分辨率

    save_path 可以省略。省略时,文件写入临时目录,文件名为 recording_<timestamp>.mp4

    父目录不存在时会自动创建;worker 无法写入目标目录时返回 400

    data 带上:

    • status —— recordingstoppedidle
    • duration —— 已录制的秒数
    • save_path —— 文件写到哪里
    • file_size_bytes —— 停止之后的文件大小

    把录像存到 文件 API 能取到的路径下。销毁宿主前先停止录制。这样文件才完整可播放。

    Windows:安全桌面

    安全桌面会拒绝输入,例如 UAC 提示或锁屏界面。单个动作返回 403data{"status": "denied", "reason": "secure-desktop-or-uipi"}

    这是 Windows 的会话边界,不是需要绕过的 bug。批量执行时,之前的动作已经完成,因此同样的拒绝会通过 200 响应中的 statusreason 返回。

    直接访问 worker API

    computer-use 也能不经 aiod 直接被访问:

    路由作用说明
    GET /healthz存活探测公开
    GET /capabilities桌面能力探测schema_version 1;设置了 API key 时需要携带
    GET /openapi.jsonworker 自己的接口契约公开
    GET /metricsPrometheus 文本设置了 API key 时需要携带

    单独部署或给 worker 做健康检查时有用。

    Human in the loop

    人可以进入 agent 正在驱动的终端、浏览器或桌面,查看运行过程,也可以接手登录或验证码,再把控制权交回去。

    daemon 不需要为此改变配置。预构建镜像通过网关提供这些查看器,每个查看器都连接到 agent 已经在使用的对象:

    查看器镜像上的路径显示什么
    noVNC/vnc/index.htmlworker 驱动的 X display;可观察,也可接管
    DevTools/browser-ui/cdp/devtools/*Chromium 的标签页,走 agent 在用的同一个 CDP
    WebShell/terminal?session_id=…一个 PTY 会话;链接由 GET /v1/shell/terminal-url 生成
    code-server/code-server/同一个文件系统上的 IDE;默认关闭,DISABLE_CODE_SERVER=false 打开
    JupyterLab/jupyter同一个文件系统上的 notebook;默认关闭,DISABLE_JUPYTER=false 打开

    Xvnc 同时是 X server 和 VNC server。人的点击直接作用于 display,worker 会在下一次截图中看到结果。

    daemon 只提供 API;单独运行的 aiod 对这些查看器路径都返回 404

    预构建镜像已经配置好这些组件。

    AIO 镜像在 DISPLAY=:99.0 上运行 Xvnc、openbox 和 Chromium,并提供 noVNC、DevTools 和 WebShell。

    Computer 镜像在此基础上设置 AIO_DESKTOP=xfce

    XFCE 会话接管 display,computer-use worker 和 aiod 一起启动。会话 D-Bus 为 AT-SPI 提供支持,Chromium 使用 --force-renderer-accessibility,因此标签页内容会出现在无障碍树中。

    相关页面