> For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt.

# 使用 YAML 格式的自动化脚本

:::info 兼容保留，建议迁移到 Midscene Test
“旧版 YAML”，特指由 `@midscene/cli` 提供的 YAML 自动化协议：工作流顶层使用 `tasks`，每个 task 使用 `flow`，平台和 Agent 等运行配置通常也写在 YAML 中，并通过 `midscene` 命令或包含 `files`、`setup`、`concurrent` 等字段的 YAML 批配置运行。

旧链路已进入维护状态：继续保证现有项目兼容，并处理必要的问题，但不再新增语法、能力、配置项或 CLI 参数。已有用例、批配置、目录结构和 `midscene` 命令可以保持不变；升级后会通过共享执行内核运行，并生成新的 Test 报告页面。新项目、新增用例和后续能力建设推荐直接使用 Midscene Test。

旧文件和 YAML 批配置使用 `midscene`，原生 `cases/steps` 文件和 TypeScript 项目配置使用 `midscene-test`。两种格式可以放在同一个仓库的不同目录中，但不能在同一个文件或同一次命令中混用。先阅读 [Midscene Test 概览](/zh/midscene-test/overview.md)，再按照[迁移到 Midscene Test](/zh/migrate-to-midscene-test.md)转换字段并切换命令。
:::

在大多数情况下，开发者编写自动化脚本只是为了执行一些简单流程，比如检查某些内容是否出现，或者验证某个关键用户路径是否可用。此时维护一个大型测试项目会显得毫无必要。

⁠Midscene 提供了一种基于 `.yaml` 文件的自动化测试方法，这有助于你专注于编写流程，而不是测试框架。

这里有一个示例，通过阅读它的内容，你应该已经理解了它的工作原理。

```yaml
page:
  url: https://www.bing.com

tasks:
  - name: 搜索天气
    flow:
      - ai: 搜索 "今日天气"
      - sleep: 3000

  - name: 检查结果
    flow:
      - aiAssert: 结果中展示了天气信息
```

:::info 样例项目

你可以在这里找到使用 YAML 脚本做自动化的样例项目

- [Web](https://github.com/web-infra-dev/midscene-example/tree/main/yaml-scripts-demo)
- [Android](https://github.com/web-infra-dev/midscene-example/tree/main/android/yaml-scripts-demo)
- [Computer（Mac/Windows/Linux）](https://github.com/web-infra-dev/midscene-example/tree/main/computer/yaml-scripts-demo)

:::

## 配置 AI 模型服务

下面以豆包 Seed 2.1 Turbo 为例：

```bash
export MIDSCENE_MODEL_BASE_URL="https://ark.cn-beijing.volces.com/api/v3"
export MIDSCENE_MODEL_API_KEY="your-api-key"
export MIDSCENE_MODEL_NAME="doubao-seed-2-1-turbo-260628"
export MIDSCENE_MODEL_FAMILY="doubao-seed"
```

将 `your-api-key` 替换为你的 API Key。

> 如需使用千问（Qwen）、GLM、Gemini 或 GPT-5 等其他模型，请参考[使用模型 API Key](/zh/model-api-setup.md)。

全部配置项请参考[模型配置](/zh/model-config.md)。

如果需要通过命令行执行 YAML 工作流，请查看 [YAML 脚本运行器](/zh/yaml-script-runner.md)，了解安装、`.env` 支持以及 `midscene` 命令的用法。

## 脚本文件结构

脚本文件使用 YAML 格式来描述自动化任务。它定义了要操作的目标（如网页或安卓应用）以及一系列要执行的步骤。

一个标准的 `.yaml` 脚本文件包含 `page`、`browser`、`web`、`android`、`ios`、`harmony` 或 `computer` 部分配置环境，可选的 `agent` 部分配置 AI Agent 行为，以及一个 `tasks` 部分来定义自动化任务。

```yaml
page:
  url: https://www.bing.com

# tasks 部分定义了要执行的一系列步骤
tasks:
  - name: 搜索天气
    flow:
      - ai: 搜索 "今日天气"
      - sleep: 3000
      - aiAssert: 结果显示天气信息
```

使用 `page:` 表示 page-level Agent。使用 `browser:` 表示一个 Agent 管理 browser 和它的 active page。`web:` 仍作为兼容入口保留；`web.mode: browser` 会映射到 BrowserAgent，普通 `web:` 会映射到 PageAgent。不要在同一份脚本里同时使用 `page`、`browser`、`web` 或已废弃的 `target`。

### `agent` 部分

`agent` 部分用于配置 AI Agent 的行为和测试报告相关选项。所有字段都是可选的。

```yaml
# AI agent 配置
agent:
  # 测试标识符，用于报告和缓存识别，可选
  testId: <string>

  # 报告组名称，可选
  groupName: <string>

  # 报告组描述，可选
  groupDescription: <string>

  # 是否生成测试报告，可选，默认 true
  generateReport: <boolean>

  # 是否自动打印报告消息，可选，默认 true
  autoPrintReportMsg: <boolean>

  # 自定义报告文件名，可选
  reportFileName: <string>

  # AI 最大重规划循环次数，可选，默认 20（UI-TARS 模型为 40）
  replanningCycleLimit: <number>

  # 提供给 AI 的补充信息，可选；default 是共享的缺省回退值
  aiContexts:
    default: <string>
    aiAct: <string>
    aiQuery: <string>

  # 缓存配置，可选
  cache:
    # 缓存策略，可选，可选值：'read-only' | 'read-write' | 'write-only'
    strategy: <string>
    # 缓存 ID，必填
    id: <string>
```

:::info Agent 配置说明

- **适用环境**：Web、iOS 和 Android 环境都支持 `agent` 配置
- **testId 优先级**：CLI 参数 > YAML agent.testId > 文件名
- **aiContexts**：提供给 AI 的补充信息，例如业务事实、规则、约束或输出要求。如果配置了 `default`，仅当本次调用和对应 API 都没有自己的 context 时才使用它。单次调用的 `context` 覆盖 API 级值，API 级值覆盖 `default`，这些值不会自动合并；空字符串会显式清空继承的用户 context。关于上下文知识的编写和传入方式，参见[为 GUI Agent 补充应用知识](/zh/provide-application-knowledge-to-gui-agent.md)。
- **aiActContext / aiActionContext**：`aiContexts.aiAct` 的已废弃兼容字段，均仍受支持。解析规则为 `aiContexts.aiAct ?? aiActContext ?? aiActionContext`；空字符串也会覆盖低优先级的兼容字段。新 YAML 脚本请使用 `aiContexts.aiAct`。
- **缓存配置**：详细用法请参考 [缓存功能文档](/zh/caching.md)

:::

#### 使用示例

```yaml
# agent 配置，适用于所有环境
agent:
  testId: "checkout-test"
  groupName: "E2E 测试套件"
  groupDescription: "完整的购物流程测试"
  generateReport: true
  autoPrintReportMsg: false
  reportFileName: "checkout-report"
  replanningCycleLimit: 30
  aiContexts:
    default: "页面中的价格单位是美元。"
    aiAct: "如果出现弹窗，点击同意。如果出现登录页面，跳过它。"
  cache:
    id: "checkout-cache"
    strategy: "read-write"

# iOS 环境配置
ios:
  launch: https://www.bing.com
  wdaPort: 8100

# 或 Android 环境配置
android:
  deviceId: s4ey59
  launch: https://www.bing.com

tasks:
  - name: 搜索天气
    flow:
      - ai: 搜索 "今日天气"
      - aiAssert: 结果显示天气信息
```

### Web target 部分

推荐的 page-level target：

```yaml
page:
  url: https://example.com
```

推荐的 browser-level target：

```yaml
browser:
  url: https://example.com
  autoFollowNewPage: true
```

兼容写法：

```yaml
web:
  mode: browser
  url: https://example.com
  autoFollowNewPage: true
```

共享配置：

```yaml
page:
  # 访问的 URL，必填。如果提供了 `serve` 参数，则提供相对路径
  url: <url>

  # 在本地路径下启动一个静态服务，可选
  serve: <root-directory>

  # 浏览器 UA，可选
  userAgent: <ua>

  # 浏览器视口宽度，可选，默认 1440
  viewportWidth: <width>

  # 浏览器视口高度，可选，默认 800
  viewportHeight: <height>

  # 浏览器设备像素比，可选，默认跟随系统
  deviceScaleFactor: <scale>

  # JSON 格式的浏览器 Cookie 文件路径，可选
  cookie: <path-to-cookie-file>

  # Chrome 下载目录（仅 Puppeteer 模式），可选
  # 相对路径会基于当前工作目录解析
  # bridgeMode 不支持该选项
  downloadPath: <path-to-download-directory>

  # 随每个请求发送的额外 HTTP 请求头（仅 Puppeteer 模式），可选
  # 适用于服务器会校验自定义请求头的场景
  # 值必须是字符串；像 true、false、纯数字这类会被 YAML 解析为非字符串的值需加引号，如 "true"
  extraHTTPHeaders:
    X-Custom-Token: my-token
    Accept-Language: en-US

  # Puppeteer 模式下等待网络空闲的策略，可选
  # `timeout` 会作用于初始打开 YAML 中的 `web.url`，以及后续 `aiTap`、`aiInput` 等操作后的等待
  # `continueOnNetworkIdleError` 只作用于初始打开 YAML 中的 `web.url`
  waitForNetworkIdle:
    # 每次网络空闲等待的超时时间，可选，默认 2000ms
    timeout: <ms>
    # 初始打开 YAML 中的 `web.url` 时，如果网络空闲等待超时，是否继续执行，可选，默认 true
    # 后续脚本执行中的等待即使超时也总是继续执行
    continueOnNetworkIdleError: <boolean>

  # 输出 aiQuery/aiAssert 结果的 JSON 文件路径，可选
  output: <path-to-output-file>

  # 是否保存日志内容到 JSON 文件，可选，默认 `false`。如果为 true，保存到 `unstableLogContent.json` 文件中。如果为字符串，则保存到该字符串指定的路径中。日志内容的结构可能会在未来发生变化。
  unstableLogContent: <boolean | path-to-unstable-log-file>

  # 是否限制页面在当前 tab 打开，可选，默认 true
  # 仅 page mode 可用，不要与 `browser:` 或 `web.mode: browser` 同时使用
  forceSameTabNavigation: <boolean>

  # BrowserAgent 是否自动继续在新打开的页面中执行，可选，默认 false
  # 仅 browser mode 可用。请使用 `browser:` 或 `web.mode: browser`
  autoFollowNewPage: <boolean>

  # CDP 连接端点，可选。设置后通过 CDP 连接到已有浏览器实例，而非启动新浏览器。
  # 与 bridgeMode 互斥，不可同时使用。
  cdpEndpoint: ws://localhost:9222/devtools/browser

  # 桥接模式，可选，默认 false，可以为 'newTabWithUrl' 或 'currentTab'。更多详情请参阅后文
  bridgeMode: false | 'newTabWithUrl' | 'currentTab'

  # 是否在桥接断开时关闭新创建的标签页，可选，默认 false
  closeNewTabsAfterDisconnect: <boolean>

  # 是否忽略 HTTPS 证书错误，可选，默认 false
  acceptInsecureCerts: <boolean>

  # 自定义 Chrome 启动参数（仅 Puppeteer 模式，不支持桥接模式），可选
  # 用于自定义 Chrome 浏览器行为，例如禁用第三方 Cookie 阻止
  # ⚠️ 安全警告：某些参数（如 --no-sandbox、--disable-web-security）可能降低浏览器安全性
  # 仅在受控的测试环境中使用
  chromeArgs:
    - '--disable-features=ThirdPartyCookiePhaseout'
    - '--disable-features=SameSiteByDefaultCookies'
    - '--window-size=1920,1080'
```

### Chrome Bridge {#chrome-bridge}

先完成 [Chrome Bridge 环境配置](/zh/bridge-mode.md)。在 `web` 中设置 `bridgeMode`：

| 配置              | 行为                 |
| --------------- | ------------------ |
| `newTabWithUrl` | 使用 `url` 创建并连接新标签页 |
| `currentTab`    | 连接当前激活标签页，忽略 `url` |

```yaml
web:
  url: https://example.com
  bridgeMode: newTabWithUrl
  closeNewTabsAfterDisconnect: true

tasks:
  - name: Check the page
    flow:
      - aiAssert: The page shows Example Domain
```

使用 [YAML 脚本运行器](/zh/yaml-script-runner.md)运行，首次连接时在插件中确认授权。`closeNewTabsAfterDisconnect` 默认 `false`；设为 `true` 时清理桥接创建的新标签页，不关闭连接前已有的标签页。

Bridge 模式与 `cdpEndpoint`、`web.mode: browser` 互斥。它复用桌面浏览器配置，以下字段会被忽略：

- `userAgent`
- `viewportWidth` / `viewportHeight`
- `deviceScaleFactor`
- `waitForNetworkIdle`
- `cookie`
- `extraHTTPHeaders`
- `downloadPath`
- `chromeArgs`

### `android` 部分

```yaml
android:
  # 设备 ID，可选，默认使用第一个连接的设备
  deviceId: <device-id>

  # 启动 URL，可选，默认使用设备当前页面
  launch: <url>

  # 输出 aiQuery/aiAssert 结果的 JSON 文件路径，可选
  output: <path-to-output-file>

  # 其他 AndroidDevice 构造函数支持的所有选项
  # 例如：androidAdbPath, remoteAdbHost, remoteAdbPort,
  # imeStrategy, displayId, autoDismissKeyboard, keyboardDismissStrategy,
  # keyboardTypeDelay, minScreenshotBufferSize, alwaysRefreshScreenInfo 等
  # 完整配置项请参考 AndroidDevice 的构造函数文档
```

:::info 查看完整的 Android 配置项

YAML 脚本现在支持 `AndroidDevice` 构造函数的所有配置选项。完整的配置项列表请参考 [Android API 参考中的 AndroidDevice](/zh/sdk/android.md#androiddevice)。

:::

#### Android 平台特定动作

Android 平台提供了一些特定的动作，可以在 YAML 脚本的 `flow` 中使用：

**`runAdbShell` - 执行 ADB Shell 命令**

在 Android 设备上执行 ADB shell 命令。传入的内容只需要包含 shell 命令本身，不要包含 `adb shell` 前缀。如需设置命令超时，请将 `timeout` 作为 `runAdbShell` 的同级字段。

```yaml
android:
  deviceId: 'test-device'

tasks:
  - name: 清除应用数据
    flow:
      - runAdbShell: 'pm clear com.example.app'

  - name: 获取电池信息
    flow:
      - runAdbShell: 'dumpsys battery'

  - name: 点击屏幕坐标
    flow:
      - runAdbShell: 'input tap 100 200'

  - name: 执行带超时的命令
    flow:
      - runAdbShell: 'dumpsys activity services'
        timeout: 60000
```

常用 ADB Shell 命令：

- `pm clear <package>` - 清除应用数据
- `dumpsys battery` - 获取电池信息
- `dumpsys window` - 获取窗口信息
- `settings get secure android_id` - 获取设备 ID
- `input tap <x> <y>` - 点击屏幕坐标
- `input keyevent <keycode>` - 发送按键事件

**`launch` - 启动应用或 URL**

启动 Android 应用或打开 URL。

```yaml
android:
  deviceId: 'test-device'

tasks:
  - name: 启动设置应用
    flow:
      - launch: com.android.settings

  - name: 打开网页
    flow:
      - launch: https://www.example.com
```

**`terminate` - 终止应用**

通过包名终止（强制停止）正在运行的 Android 应用。

```yaml
android:
  deviceId: 'test-device'

tasks:
  - name: 终止设置应用
    flow:
      - terminate: com.android.settings
```

### `ios` 部分

```yaml
ios:
  # WebDriverAgent 端口，可选，默认 8100
  wdaPort: <port>

  # WebDriverAgent 主机地址，可选，默认 localhost
  wdaHost: <host>

  # 网关带路径前缀时，用 wdaBaseUrl 替代 wdaHost/wdaPort。
  # 同时设置 wdaBaseUrl 与 wdaHost 或 wdaPort 会报错。
  # wdaBaseUrl: <url>

  # 可单独设置 MJPEG 流地址，包括网关路径；不能与 wdaMjpegPort 同时设置。
  # wdaMjpegUrl: <url>

  # 本地 MJPEG 流端口，可选。与 wdaMjpegUrl 二选一。
  # wdaMjpegPort: <port>

  # 是否自动关闭键盘，可选，默认 false
  autoDismissKeyboard: <boolean>

  # 启动 URL 或应用包名，可选，默认使用设备当前页面
  launch: <url-or-bundle-id>

  # 输出 aiQuery/aiAssert 结果的 JSON 文件路径，可选
  output: <path-to-output-file>

  # 是否保存日志内容到 JSON 文件，可选，默认 `false`。如果为 true，保存到 `unstableLogContent.json` 文件中。如果为字符串，则保存到该字符串指定的路径中。日志内容的结构可能会在未来发生变化。
  unstableLogContent: <boolean | path-to-unstable-log-file>

  # 其他 IOSDevice 构造函数支持的所有选项
  # 完整配置项请参考 IOSDevice 的构造函数文档
```

连接带路径前缀的网关时，只设置 `wdaBaseUrl`。MJPEG 流可以使用单独的地址：

```yaml
ios:
  wdaBaseUrl: ${WDA_BASE_URL}
  wdaMjpegUrl: ${WDA_MJPEG_URL}
```

运行脚本前，请设置这两个环境变量。Studio Recorder 导出的 YAML 也引用环境变量。这样，网关路径和访问令牌不会写入文件。

:::info 查看完整的 iOS 配置项

YAML 脚本现在支持 `IOSDevice` 构造函数的所有配置选项。完整的配置项列表请参考 [iOS API 参考中的 IOSDevice](/zh/sdk/ios.md#iosdevice)。

:::

#### iOS 平台特定动作

iOS 平台提供了一些特定的动作，可以在 YAML 脚本的 `flow` 中使用：

**`runWdaRequest` - 执行 WebDriverAgent API 请求**

在 iOS 设备上直接执行 WebDriverAgent API 请求。

```yaml
ios:
  launch: 'com.apple.mobilesafari'

tasks:
  - name: 通过 WDA 按下主屏幕按钮
    flow:
      - runWdaRequest:
          method: POST
          endpoint: /session/test/wda/pressButton
          data:
            name: home

  - name: 获取设备信息
    flow:
      - runWdaRequest:
          method: GET
          endpoint: /wda/device/info
```

参数：

- `method`（字符串，必需）：HTTP 方法（GET、POST、DELETE 等）
- `endpoint`（字符串，必需）：WebDriverAgent API 端点
- `data`（任意类型，可选）：请求体数据

常用 WebDriverAgent 端点：

- `/wda/screen` - 获取屏幕信息
- `/wda/device/info` - 获取设备信息
- `/session/{sessionId}/wda/pressButton` - 按硬件按钮
- `/session/{sessionId}/wda/apps/launch` - 启动应用
- `/session/{sessionId}/wda/apps/terminate` - 终止应用
- `/session/{sessionId}/wda/apps/activate` - 激活应用

**`launch` - 启动应用或 URL**

启动 iOS 应用或打开 URL。

```yaml
ios:
  wdaPort: 8100

tasks:
  - name: 启动设置应用
    flow:
      - launch: com.apple.Preferences

  - name: 打开网页
    flow:
      - launch: https://www.example.com
```

**`terminate` - 终止应用**

通过 Bundle ID 终止（关闭）正在运行的 iOS 应用。

```yaml
ios:
  wdaPort: 8100

tasks:
  - name: 终止设置应用
    flow:
      - terminate: com.apple.Preferences
```

### `harmony` 部分

`harmony` 部分用于通过 HDC 进行 HarmonyOS 设备自动化。设备通过 `hdc` 连接,运行前请先确认 `hdc list targets` 能列出你的设备。

```yaml
harmony:
  # 要连接的 HarmonyOS 设备 ID,可选,默认使用第一个已连接的设备。
  deviceId: <device-id>

  # 要启动的应用,可选,默认使用设备当前屏幕。
  launch: <bundle-name>

  # HDC 可执行文件路径,可选。
  hdcPath: <path-to-hdc>

  # 输入完成后是否自动收起键盘,可选,默认为 true。
  autoDismissKeyboard: <boolean>

  # 应用名到 bundle name 或显式 bundle/Ability 目标的自定义映射,可选。
  # 用户提供的映射优先级高于默认映射。
  appNameMapping:
    <app-name>: <bundle-name-or-bundle/ability>

  # 用于输出 aiQuery/aiAssert 结果的 JSON 文件路径,可选。
  output: <path-to-output-file>

  # HarmonyDevice 构造函数支持的其他所有选项
```

#### HarmonyOS 平台专属动作

**`launch` - 启动应用**

通过 bundle name 或显式 `bundle/Ability` 目标启动 HarmonyOS 应用。

```yaml
harmony:
  deviceId: 'test-device'
  appNameMapping:
    视频: com.example.video/PhoneAbility

tasks:
  - name: 启动应用
    flow:
      - launch: 视频
```

**`terminate` - 终止应用**

通过 Bundle 名或映射的应用名终止(强制停止)正在运行的 HarmonyOS 应用。

```yaml
harmony:
  deviceId: 'test-device'

tasks:
  - name: 终止应用
    flow:
      - terminate: com.example.app
```

**`runHdcShell` - 执行 HDC Shell 命令**

在 HarmonyOS 设备上执行 HDC shell 命令。

```yaml
harmony:
  deviceId: 'test-device'

tasks:
  - name: 导出窗口信息
    flow:
      - runHdcShell:
          command: 'hidumper -s WindowManagerService -a'
```

### `computer` 部分

`computer` 部分用于 PC 桌面自动化。它允许你控制桌面环境，包括鼠标移动、键盘输入和屏幕查询。

```yaml
computer:
  # 使用的显示器 ID，可选，默认使用主显示器
  displayId: <display-id>

  # 输出 aiQuery/aiAssert 结果的 JSON 文件路径，可选
  output: <path-to-output-file>
```

#### 使用示例

```yaml
computer: {}

tasks:
  - name: 打开浏览器并搜索
    flow:
      - aiAct: 按下 Cmd+Space
      - sleep: 500
      - aiAct: 输入 "Safari" 并按回车
      - sleep: 2000
      - aiAct: 按下 Cmd+L 聚焦地址栏
      - aiAct: 输入 "https://www.bing.com"
      - aiAct: 按下回车
      - sleep: 3000
      - aiAct: 在搜索框中输入 "今日天气" 并按回车
      - aiAssert: 结果显示天气信息
```

:::info 平台说明

上面的示例脚本使用 macOS 命令。对于 Windows，请修改脚本：

- 使用 `按下 Windows 键` 代替 `按下 Cmd+Space`
- 使用 `输入 "Chrome"` 代替 `输入 "Safari"`
- 使用 `按下 Ctrl+L` 代替 `按下 Cmd+L`

:::

### `tasks` 部分

`tasks` 部分是一个数组，定义了脚本执行的步骤。记得在每个步骤前添加 `-` 符号，表明这些步骤是个数组。

`flow` 部分的接口与 [API](/zh/reference.md#common) 几乎相同，除了一些参数的嵌套层级。

```yaml
tasks:
  - name: <name>
    continueOnError: <boolean> # 可选，错误时是否继续执行下一个任务，默认 false
    flow:
      # 自动规划(Auto Planning, .ai)
      # ----------------

      # 执行一个交互，`ai` 是 `aiAct` 的简写方式
      - ai: <prompt>
        cacheable: <boolean> # 可选，当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
        deepThink: <boolean> # 可选，引导 aiAct 注重任务拆解，并将任务 Planning 和 UI 元素定位拆解为不同的模型调用。默认值为 false。
        deepLocate: <boolean> # 可选，在 aiAct 执行过程中为 UI 元素定位开启深度定位。默认值为 false。

      # 这种用法与 `ai` 相同
      # 注意：在之前版本中也被写作 `aiAction`，当前版本兼容两种写法
      - aiAct: <prompt>
        cacheable: <boolean> # 可选，当启用 [缓存功能](./caching.mdx) 时，是否允许缓存当前 API 调用结果。默认值为 True
        deepThink: <boolean> # 可选，引导 aiAct 注重任务拆解，并将任务 Planning 和 UI 元素定位拆解为不同的模型调用。默认值为 false。
        deepLocate: <boolean> # 可选，在 aiAct 执行过程中为 UI 元素定位开启深度定位。默认值为 false。

      # 即时操作(Instant Action, .aiTap, .aiHover, .aiInput, .aiKeyboardPress, .aiScroll)
      # ----------------

      # 点击一个元素，用 prompt 描述元素位置
      - aiTap: <prompt>
        deepLocate: <boolean> # 可选，是否为该元素开启深度定位。默认值为 False
        xpath: <xpath> # 可选，目标元素的 xpath 路径，用于执行当前操作。如果提供了这个 xpath，Midscene 会优先使用该 xpath 来找到元素，然后依次使用缓存和 AI 模型。默认值为空
        cacheable: <boolean> # 可选，当启用 [缓存功能](./caching.mdx) 时，是否允许缓存当前 API 调用结果。默认值为 True
        fileChooserAccept: <path> | [<path1>, <path2>] # 可选，当点击触发文件选择器时，指定要上传的文件路径；仅在 web 中可用

      # 鼠标悬停一个元素，用 prompt 描述元素位置
      - aiHover: <prompt>
        deepLocate: <boolean> # 可选，是否为该元素开启深度定位。默认值为 False
        xpath: <xpath> # 可选，目标元素的 xpath 路径，用于执行当前操作。如果提供了这个 xpath，Midscene 会优先使用该 xpath 来找到元素，然后依次使用缓存和 AI 模型。默认值为空

        cacheable: <boolean> # 可选，当启用 [缓存功能](./caching.mdx) 时，是否允许缓存当前 API 调用结果。默认值为 True

      # 输入文本到一个元素，用 prompt 描述元素位置
      - aiInput: <prompt> # 要输入文本的元素
        value: <输入框的最终文本内容>
        deepLocate: <boolean> # 可选，是否为该元素开启深度定位。默认值为 False
        xpath: <xpath> # 可选，目标元素的 xpath 路径，用于执行当前操作。如果提供了这个 xpath，Midscene 会优先使用该 xpath 来找到元素，然后依次使用缓存和 AI 模型。默认值为空
        cacheable: <boolean> # 可选，当启用 [缓存功能](./caching.mdx) 时，是否允许缓存当前 API 调用结果。默认值为 True

      # 在元素上按下某个按键（如 Enter，Tab，Escape 等），用 prompt 描述元素位置
      - aiKeyboardPress: <prompt> # 要按键的目标元素
        keyName: <按键>
        deepLocate: <boolean> # 可选，是否为该元素开启深度定位。默认值为 False
        xpath: <xpath> # 可选，目标元素的 xpath 路径，用于执行当前操作。如果提供了这个 xpath，Midscene 会优先使用该 xpath 来找到元素，然后依次使用缓存和 AI 模型。默认值为空

        cacheable: <boolean> # 可选，当启用 [缓存功能](./caching.mdx) 时，是否允许缓存当前 API 调用结果。默认值为 True

      # 全局滚动，或滚动 prompt 描述的元素
      - aiScroll: <prompt> # 可选，执行滚动的元素
        scrollType: 'singleAction' # 或 'scrollToBottom' | 'scrollToTop' | 'scrollToRight' | 'scrollToLeft'，默认值为 'singleAction'
        direction: 'down' # 或 'up' | 'left' | 'right'，默认值为 'down'。仅在 scrollType 为 singleAction 时生效
        distance: <number> # 可选，滚动距离，单位为设备的逻辑像素，
        # 也就是自定义设备接入时 size() 返回的宽高所使用的坐标单位。设置为 null 表示由 Midscene 自动决定。
        # 执行时，该距离在触摸设备上会转换为滑动手势的移动距离，在 Web／桌面端会转换为滚轮滚动增量。
        # 页面内容最终的移动距离不保证与该值相同。
        deepLocate: <boolean> # 可选，是否为该元素开启深度定位。默认值为 False
        xpath: <xpath> # 可选，目标元素的 xpath 路径，用于执行当前操作。如果提供了这个 xpath，Midscene 会优先使用该 xpath 来找到元素，然后依次使用缓存和 AI 模型。默认值为空

        cacheable: <boolean> # 可选，当启用 [缓存功能](./caching.mdx) 时，是否允许缓存当前 API 调用结果。默认值为 True

      # 在报告文件中记录当前截图，并添加描述
      - recordToReport: <title> # 可选，截图的标题，如果未提供，则标题为 'untitled'
        content: <content> # 可选，截图的描述

      # 数据提取
      # ----------------

      # 执行一个查询，返回一个 JSON 对象
      - aiQuery: <prompt> # 记得在提示词中描述输出结果的格式
        name: <name> # 查询结果在 JSON 输出中的 key

      # 更多 API
      # ----------------

      # 等待某个条件满足，并设置超时时间(ms，可选，默认 30000)
      - aiWaitFor: <prompt>
        timeout: <ms>

      # 执行一个断言
      - aiAssert: <prompt>
        errorMessage: <error-message> # 可选，当断言失败时打印的错误信息。
        name: <name> # 可选，给断言一个名称，会在 JSON 输出中作为 key 使用

      - aiBoolean: <prompt>
        name: <name> # 可选，给布尔结果一个名称，会在 JSON 输出中作为 key 使用

      # 运行一个 Gherkin Scenario。此功能从 Midscene 1.10 开始支持，目前仍处于 Beta 阶段。
      - runGherkinScenario: |
          Scenario: 添加待办事项
            Given 待办事项页面已经打开
            When 我添加一条名为“买牛奶”的待办事项
            Then 待办事项列表中应该包含“买牛奶”

      # 等待一定时间
      - sleep: <ms>

      # 在 web 页面上下文中执行一段 JavaScript 代码
      - javascript: <javascript>
        name: <name> # 可选，给返回值一个名称，会在 JSON 输出中作为 key 使用

  - name: <name>
    flow:
      # ...
```

`runGherkinScenario` 从 Midscene 1.10 开始支持，目前仍处于 Beta 阶段。支持规则和限制请参考 [BDD 风格脚本（Gherkin）](/zh/advanced/bdd-style-scripts-with-gherkin.md)。

#### 步骤结果名称

带有 `name` 的步骤会把结果写入当前 YAML 运行结果和 JSON 输出中。使用 `name` 标记需要出现在运行结果里的值。

```yaml
tasks:
  - name: 保存提取结果
    flow:
      - aiString: 读取页面中的商品 id
        name: product_id

      - aiQuery: 提交商品 id 后，获取搜索结果
        name: search_result
```

#### 使用 `aiTap` 上传文件

当点击某个按钮会弹出文件选择器时，可以在 `aiTap` 步骤上直接设置 `fileChooserAccept`。它支持单个路径，也支持路径数组。

```yaml
tasks:
  - name: 上传单个文件
    flow:
      - aiTap: 选择文件按钮
        fileChooserAccept: ./fixtures/document.pdf

  - name: 上传多个文件
    flow:
      - aiTap: 上传图片按钮
        fileChooserAccept:
          - ./fixtures/image1.jpg
          - ./fixtures/image2.png
```

如果你已经在用 `locate` 对象写 `prompt`、`images` 等定位信息，`fileChooserAccept` 仍然要和 `locate` 保持同级，不要放到 `locate` 或 `aiTap` 的嵌套对象里：

```yaml
tasks:
  - name: 带 locate 的文件上传
    flow:
      - aiTap:
        locate:
          prompt: 点击上传按钮
        fileChooserAccept: ./fixtures/document.pdf
```

注意：

- `fileChooserAccept` 仅在 web 页面（Playwright、Puppeteer 或 Chrome extension Bridge mode）中可用。
- 相对路径会基于当前命令执行目录解析，而不是基于 YAML 文件所在目录解析。
- 如果文件不存在，脚本会在执行点击前直接报错。
- Chrome extension Bridge mode 上传本地文件时，需要在 `chrome://extensions` > Midscene > “Details” 中开启插件的 “Allow access to file URLs” 权限。开启后请从目标 `http(s)://` 页面重新连接桥接模式。
- Chrome extension Bridge mode 不支持目录上传输入框（`webkitdirectory` / `directory`）。如需上传目录，请使用 Playwright。

#### 使用图像提示

对于支持在提示词中附带图像的步骤（参见 [API 参考](/zh/reference.md#prompting-with-images)），可以把提示词改写为对象，并通过设置 `images` 字段（一个包含 `name` 和 `url` 的对象数组）来附加图像。该对象包含以下字段：

- `prompt`：发送给模型的文本描述。
- `images`（可选）：提示词引用的参考图像，每一项需要提供 `name` 和 `url`。
- `convertHttpImage2Base64`（可选）：在图片链接无法公开访问时，将 HTTP 链接转换为 Base64 再发送给模型。

图片 URL 可以是本地路径、Base64 字符串或远程链接。如果图片链接无法被模型访问，请设置 `convertHttpImage2Base64: true`，Midscene 会将图像下载后以 Base64 字符串的形式发送给模型。

对于 `aiTap`、`aiHover`、`aiDoubleClick`、`aiRightClick` 等交互操作，请把文本和图像配置写在 `locate` 字段中，`locate` 与操作指令同级。

```yaml
tasks:
  - name: 校验品牌一致性
    flow:
      - aiHover:
        locate:
          prompt: 将鼠标移动到包含 GitHub 标志的区域。
          images:
            - name: GitHub 标志
              url: https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png
          convertHttpImage2Base64: true

      - aiTap:
        locate:
          prompt: 点击包含 GitHub 标志的区域。
          images:
            - name: GitHub 标志
              url: https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png
          convertHttpImage2Base64: true
```

> 旧的嵌套写法（将 `locate` 缩进到操作指令内部，例如 `aiTap: \n    locate: ...`）仍然支持，但不推荐使用。

对于 `aiAct`（及其简写 `ai`），以及 `aiAsk`、`aiQuery`、`aiBoolean`、`aiNumber`、`aiString`、`aiAssert` 等视觉问答类步骤，都可以直接在操作指令下设置 `prompt` 和 `images` 字段。

```yaml
tasks:
  - name: 校验品牌一致性
    flow:
      - aiAssert:
          prompt: 判断页面上是否出现该图像。
          images:
            - name: 目标标志
              url: https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png
          convertHttpImage2Base64: true
```

## 注意事项

### `agent.runYaml` 只会解析 `tasks` 字段

当使用 `agent.runYaml()` api 时，YAML 文件中只有 `tasks` 字段会被解析和执行。

因为此时 agent 已经在 js 脚本中完成初始化，无法根据 YAML 中的 `agent` 配置再次初始化。
