API 参考(公共部分)

构造器

Midscene 针对每个不同环境都有对应的 Agent。每个 Agent 的构造函数都接受一组共享的配置项(设备、报告、缓存、AI 配置、钩子等),然后再叠加平台专属的配置,比如浏览器里的导航控制或 Android 的 ADB 配置。

你可以通过下面的链接查看各 Agent 的导入路径和平台专属参数:

参数

这些 Agent 有一些相同的构造参数:

  • generateReport: boolean: 如果为 true,则生成报告文件。默认值为 true。
  • reportFileName: string: 报告文件的名称,默认值由 midscene 内部生成。
  • autoPrintReportMsg: boolean: 如果为 true,则打印报告消息。默认值为 true。
  • cacheId: string | undefined: 如果配置,则使用此 cacheId 保存或匹配缓存。默认值为 undefined,也就是不启用缓存。
  • aiActContext: string: 调用 agent.aiAct() 时,发送给 AI 模型的背景知识,比如 "有 cookie 对话框时先关闭它",默认值为空。此前名为 aiActionContext,旧名称仍然兼容。
  • replanningCycleLimit: number: aiAct 的最大重规划次数。默认值为 20(UI-TARS 模型默认 40)。推荐通过 agent 入参设置;MIDSCENE_REPLANNING_CYCLE_LIMIT 环境变量仅作兼容读取。
  • waitAfterAction: number: 每次动作执行后的等待时间(毫秒)。这让 UI 有时间稳定,然后再执行下一个动作。默认值为 300 毫秒。
  • onTaskStartTip: (tip: string) => void | Promise<void>:可选回调,在每个子任务执行开始前收到一条可读的任务描述提示。默认值为 undefined。

自定义模型

modelConfig: Record<string, string | number> 可选。它允许你通过代码配置模型,而不是通过环境变量。

如果在 Agent 初始化时提供了 modelConfig系统环境变量中的模型配置将全部被忽略,仅使用该对象中的值。 这里可配置的 key / value 与 模型配置 文档中说明的内容完全一致。你也可以参考 模型策略 中的说明。

基础示例(所有意图共用同一模型):

const agent = new PuppeteerAgent(page, {
  modelConfig: {
    MIDSCENE_MODEL_NAME: 'qwen3-vl-plus',
    MIDSCENE_MODEL_BASE_URL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
    MIDSCENE_MODEL_API_KEY: 'sk-...',
    MIDSCENE_MODEL_FAMILY: 'qwen3-vl'
  }
});

为不同任务类型配置不同模型(使用针对意图的环境变量键):

const agent = new PuppeteerAgent(page, {
  modelConfig: {
    // 默认
    MIDSCENE_MODEL_NAME: 'qwen3-vl-plus',
    MIDSCENE_MODEL_API_KEY: 'sk-default-key',
    MIDSCENE_MODEL_BASE_URL: '.....',
    MIDSCENE_MODEL_FAMILY: 'qwen3-vl',

    // planning 意图
    MIDSCENE_PLANNING_MODEL_NAME: 'gpt-5.1',
    MIDSCENE_PLANNING_MODEL_API_KEY: 'sk-planning-key',
    MIDSCENE_PLANNING_MODEL_BASE_URL: '...',

    // insight 意图
    MIDSCENE_INSIGHT_MODEL_NAME: 'qwen-vl-plus',
    MIDSCENE_INSIGHT_MODEL_API_KEY: 'sk-insight-key'
  }
});

自定义 OpenAI 客户端

createOpenAIClient: (openai, options) => Promise<OpenAI | undefined> 可选。它允许你包装 OpenAI 客户端实例,用于集成可观测性工具(如 LangSmith、LangFuse)或应用自定义中间件。

参数说明:

  • openai: OpenAI - Midscene 创建的基础 OpenAI 客户端实例,已包含所有必要配置(API 密钥、基础 URL、代理等)
  • options: Record<string, unknown> - OpenAI 初始化选项,包括:
    • baseURL?: string - API 接入地址
    • apiKey?: string - API 密钥
    • dangerouslyAllowBrowser: boolean - 在 Midscene 中始终为 true
    • 其他 OpenAI 配置选项

返回值:

  • 返回包装后的 OpenAI 客户端实例,或返回 undefined 表示使用原始实例

示例(集成 LangSmith):

import { wrapOpenAI } from 'langsmith/wrappers';

const agent = new PuppeteerAgent(page, {
  createOpenAIClient: async (openai, options) => {
    // 为规划任务包装 LangSmith
    if (options.baseURL?.includes('planning')) {
      return wrapOpenAI(openai, {
        metadata: { task: 'planning' }
      });
    }

    // 其他任务返回原始客户端
    return openai;
  }
});

注意: 对于 LangSmith 和 Langfuse 集成,推荐使用 模型配置 中介绍的环境变量方式,无需编写 createOpenAIClient 代码。如果你提供了自定义的客户端包装函数,它会覆盖环境变量的自动集成行为。

交互方法

这些是 Midscene 中各类 Agent 的主要 API。

自动规划 v.s. 即时操作

在 Midscene 中,你可以选择使用自动规划(Auto Planning)或即时操作(Instant Action)。

  • agent.ai() 是自动规划(Auto Planning):Midscene 会自动规划操作步骤并执行。它更智能,更像流行的 AI Agent 风格,但可能较慢,且效果依赖于 AI 模型的质量。
  • agent.aiTap(), agent.aiHover(), agent.aiInput(), agent.aiKeyboardPress(), agent.aiScroll(), agent.aiDoubleClick(), agent.aiRightClick() 是即时操作(Instant Action):Midscene 会直接执行指定的操作,而 AI 模型只负责底层任务,如定位元素等。这种接口形式更快、更可靠。当你完全确定自己想要执行的操作时,推荐使用这种接口形式。

agent.aiAct()agent.ai()

这个方法允许你通过自然语言描述一系列 UI 操作步骤。Midscene 会自动规划这些步骤并执行。

向后兼容

这个接口在之前版本里也被写为 aiAction(),当前的版本兼容两种写法。为了保持代码的一致性,建议使用新的 aiAct() 方法。

  • 类型
function aiAct(
  prompt: string,
  options?: {
    cacheable?: boolean;
    deepThink?: 'unset' | true | false;
    fileChooserAccept?: string | string[];
  },
): Promise<void>;
function ai(prompt: string): Promise<void>; // 简写形式
  • 参数:

    • prompt: string - 用自然语言描述的操作内容
    • options?: Object - 可选,一个配置对象,包含:
      • cacheable?: boolean - 当启用 缓存功能 时,是否允许缓存当前 API 调用结果。默认值为 true
      • deepThink?: 'unset' | true | false - 当模型支持时(取决于 MIDSCENE_MODEL_FAMILY),是否开启规划阶段的深度思考能力。默认值为 'unset'(等同于省略该参数),跟随模型服务商的默认策略。详情参阅 deepThink 说明
      • fileChooserAccept?: string | string[] - 当文件选择器弹出时,指定对应的文件路径。可以是单个文件路径或路径数组。仅在 web 页面(Playwright、Puppeteer)中可用。
        • 注意:如果文件输入框不支持多文件(没有 multiple 属性),但是传入了多个文件,会抛出错误。
        • 注意:如果点击触发了文件选择器但没有传入 fileChooserAccept 参数,文件选择器会被忽略,页面可以继续正常操作。
  • 返回值:

    • 返回一个 Promise。当所有步骤执行完成时解析为 void;若执行失败,则抛出错误。
  • 示例:

// 基本用法
await agent.aiAct('在搜索框中输入 "JavaScript",然后点击搜索按钮');

// 使用 .ai 简写形式
await agent.ai(
  '点击页面顶部的登录按钮,然后在用户名输入框中输入 "test@example.com"',
);

// 使用 ui-tars 模型时,可以使用更目标驱动的提示词
await agent.aiAct('发布一条微博,内容为 "Hello World"');
Tip

在实际运行时,Midscene 会将用户指令规划(Planning)成多个步骤,然后逐步执行。如果 Midscene 认为无法执行,将抛出一个错误。

为了获得最佳效果,请尽可能提供清晰、详细的步骤描述。

关联文档:

agent.aiTap()

点击某个元素

  • 类型
function aiTap(locate: string | Object, options?: Object): Promise<void>;
  • 参数:

    • locate: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • options?: Object - 可选,一个配置对象,包含:
      • deepThink?: boolean - 是否开启深度思考。如果为 true,Midscene 会调用 AI 模型两次以精确定位元素,从而提升准确性。默认值为 false。对于新一代模型(如 Qwen3 / Doubao 1.6 / Gemini 3),带来的收益不明显。
      • xpath?: string - 目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
      • cacheable?: boolean - 当启用 缓存功能 时,是否允许缓存当前 API 调用结果。默认值为 true
      • fileChooserAccept?: string | string[] - 当文件选择器弹出时,指定对应的文件路径。可以是单个文件路径或路径数组。仅在 web 页面(Playwright、Puppeteer)中可用。
        • 注意:如果文件输入框不支持多文件(没有 multiple 属性),但是传入了多个文件,会抛出错误。
        • 注意:如果点击触发了文件选择器但没有传入 fileChooserAccept 参数,文件选择器会被忽略,页面可以继续正常操作。
  • 返回值:

    • Promise<void>
  • 示例:

await agent.aiTap('页面顶部的登录按钮');

// 使用 deepThink 功能精确定位元素
await agent.aiTap('页面顶部的登录按钮', { deepThink: true });

// 文件上传:点击上传按钮并选择文件
await agent.aiTap('选择文件按钮', { fileChooserAccept: ['./document.pdf'] });
await agent.aiTap('上传图片', { fileChooserAccept: ['./image1.jpg', './image2.png'] });

agent.aiHover()

仅在 web 页面中可用,在 Android 下不可用

鼠标悬停某个元素上。

  • 类型
function aiHover(locate: string | Object, options?: Object): Promise<void>;
  • 参数:

    • locate: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • options?: Object - 可选,一个配置对象,包含:
      • deepThink?: boolean - 是否开启深度思考。如果为 true,Midscene 会调用 AI 模型两次以精确定位元素,从而提升准确性。默认值为 false。对于新一代模型(如 Qwen3 / Doubao 1.6 / Gemini 3),带来的收益不明显。
      • xpath?: string - 目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
      • cacheable?: boolean - 当启用 缓存功能 时,是否允许缓存当前 API 调用结果。默认值为 true
  • 返回值:

    • Promise<void>
  • 示例:

await agent.aiHover('页面顶部的登录按钮');

agent.aiInput()

在某个元素中输入文本。

  • 类型
// 推荐用法:定位提示在前,其他选项在 opt 中
function aiInput(
  locate: string | Object,
  opt: {
    value: string | number;
    deepThink?: boolean;
    xpath?: string;
    cacheable?: boolean;
    autoDismissKeyboard?: boolean;
    mode?: 'replace' | 'clear' | 'typeOnly';
  },
): Promise<void>;

// 兼容用法:保留向后兼容性
function aiInput(
  value: string | number,
  locate: string | Object,
  options?: Object,
): Promise<void>;
  • 参数:

    推荐用法

    • locate: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • opt: Object - 配置对象,包含:
      • value: string | number - 必填,要输入的文本内容。
        • mode'replace' 时:文本将替换输入框中的所有现有内容。
        • mode'typeOnly' 时:直接输入文本,不会先清空输入框。
        • mode'clear' 时:会忽略文本内容,仅清空输入框。
      • deepThink?: boolean - 是否开启深度思考。如果为 true,Midscene 会调用 AI 模型两次以精确定位元素,从而提升准确性。默认值为 false。对于新一代模型(如 Qwen3 / Doubao 1.6 / Gemini 3),带来的收益不明显。
      • xpath?: string - 目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
      • cacheable?: boolean - 当启用 缓存功能 时,是否允许缓存当前 API 调用结果。默认值为 true
      • autoDismissKeyboard?: boolean - 如果为 true,则键盘会在输入文本后自动关闭,仅在 Android/iOS 中有效。默认值为 true。
      • mode?: 'replace' | 'clear' | 'typeOnly' - 输入模式。(默认值: 'replace')
        • 'replace': 先清空输入框,然后输入文本。
        • 'typeOnly': 直接输入文本,不会先清空输入框。
        • 'clear': 清空输入框,不会输入新的文本。

    兼容用法(已过时,但仍然支持):

    • value: string | number - 要输入的文本内容。
    • locate: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • options?: Object - 可选的配置对象,类型与推荐用法中的 opt 类型相同。
  • 返回值:

    • Promise<void>
  • 示例:

// 推荐用法
await agent.aiInput('搜索框', { value: 'Hello World' });

// 兼容用法(不推荐)
await agent.aiInput('Hello World', '搜索框');
关于签名变更

我们最近更新了 aiInput 的 API 签名,将定位提示作为第一个参数,使得参数顺序更直观。旧的签名 aiInput(value, locate, options) 仍然完全兼容,但建议新代码使用推荐的签名。

agent.aiKeyboardPress()

按下键盘上的某个键。

  • 类型
// 推荐用法:定位提示在前,其他选项在 opt 中
function aiKeyboardPress(
  locate: string | Object,
  opt: {
    keyName: string;
    deepThink?: boolean;
    xpath?: string;
    cacheable?: boolean;
  },
): Promise<void>;

// 兼容用法:保留向后兼容性
function aiKeyboardPress(
  key: string,
  locate?: string | Object,
  options?: Object,
): Promise<void>;
  • 参数:

    推荐用法

    • locate: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • opt: Object - 配置对象,包含:
      • keyName: string - 必填,要按下的键,如 EnterTabEscape 等。不支持组合键。可在我们的源码中查看完整的按键名称列表
      • deepThink?: boolean - 是否开启深度思考。如果为 true,Midscene 会调用 AI 模型两次以精确定位元素,从而提升准确性。默认值为 false。对于新一代模型(如 Qwen3 / Doubao 1.6 / Gemini 3),带来的收益不明显。
      • xpath?: string - 目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
      • cacheable?: boolean - 当启用 缓存功能 时,是否允许缓存当前 API 调用结果。默认值为 true

    兼容用法(已过时,但仍然支持):

    • key: string - 要按下的键,如 EnterTabEscape 等。不支持组合键。
    • locate?: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • options?: Object - 可选的配置对象,类型与推荐用法中的 opt 类型相同。。
  • 返回值:

    • Promise<void>
  • 示例:

// 推荐用法
await agent.aiKeyboardPress('搜索框', { keyName: 'Enter' });

// 兼容用法(不推荐)
await agent.aiKeyboardPress('Enter', '搜索框');
关于签名变更

我们最近更新了 aiKeyboardPress 的 API 签名,将定位提示作为第一个参数,使得参数顺序更直观。旧的签名 aiKeyboardPress(key, locate, options) 仍然完全兼容,但建议新代码使用推荐的签名。

agent.aiScroll()

滚动页面或某个元素。

  • 类型
// 推荐用法:定位提示在前,其他选项在 opt 中
function aiScroll(
  locate: string | Object | undefined,
  opt: {
    scrollType?: 'singleAction' | 'scrollToBottom' | 'scrollToTop' | 'scrollToRight' | 'scrollToLeft';
    direction?: 'down' | 'up' | 'left' | 'right';
    distance?: number | null;
    deepThink?: boolean;
    xpath?: string;
    cacheable?: boolean;
  },
): Promise<void>;

// 兼容用法:保留向后兼容性
function aiScroll(
  scrollParam: PlanningActionParamScroll,
  locate?: string | Object,
  options?: Object,
): Promise<void>;
  • 参数:

    推荐用法

    • locate: string | Object | undefined - 用自然语言描述的元素定位,或使用图片作为提示词。如果未传入或为 undefined,Midscene 会在当前鼠标位置滚动。
    • opt: Object - 配置对象,包含:
      • scrollType?: 'singleAction' | 'scrollToBottom' | 'scrollToTop' | 'scrollToRight' | 'scrollToLeft' - 滚动类型,默认值为 singleAction
      • direction?: 'down' | 'up' | 'left' | 'right' - 滚动方向,默认值为 down。仅在 scrollTypesingleAction 时生效。不论是 Android 还是 Web,这里的滚动方向都是指页面哪个方向的内容会进入屏幕。比如当滚动方向是 down 时,页面下方被隐藏的内容会从屏幕底部开始逐渐向上露出。
      • distance?: number | null - 滚动距离,单位为像素。设置为 null 表示由 Midscene 自动决定。
      • deepThink?: boolean - 是否开启深度思考。如果为 true,Midscene 会调用 AI 模型两次以精确定位元素,从而提升准确性。默认值为 false。对于新一代模型(如 Qwen3 / Doubao 1.6 / Gemini 3),带来的收益不明显。
      • xpath?: string - 目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
      • cacheable?: boolean - 当启用 缓存功能 时,是否允许缓存当前 API 调用结果。默认值为 true

    兼容用法(已过时,但仍然支持):

    • scrollParam: PlanningActionParamScroll - 滚动参数(包含 scrollType、direction、distance)。
    • locate?: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • options?: Object - 可选的配置对象,类型与推荐用法中的 opt 类型相同。。
  • 返回值:

    • Promise<void>
  • 示例:

// 推荐用法
await agent.aiScroll('表单区域', {
  scrollType: 'singleAction',
  direction: 'up',
  distance: 100,
});

// 兼容用法(不推荐)
await agent.aiScroll(
  { scrollType: 'singleAction', direction: 'up', distance: 100 },
  '表单区域',
);
关于签名变更

我们最近更新了 aiScroll 的 API 签名,将定位提示作为第一个参数,使得参数顺序更直观。旧的签名 aiScroll(scrollParam, locate, options) 仍然完全兼容,但建议新代码使用推荐的签名。

agent.aiDoubleClick()

双击某个元素。

  • 类型
function aiDoubleClick(locate: string | Object, options?: Object): Promise<void>;
  • 参数:

    • locate: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • options?: Object - 可选,一个配置对象,包含:
      • deepThink?: boolean - 是否开启深度思考。如果为 true,Midscene 会调用 AI 模型两次以精确定位元素,从而提升准确性。默认值为 false。对于新一代模型(如 Qwen3 / Doubao 1.6 / Gemini 3),带来的收益不明显。
      • xpath?: string - 目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
      • cacheable?: boolean - 当启用 缓存功能 时,是否允许缓存当前 API 调用结果。默认值为 true
  • 返回值:

    • Promise<void>
  • 示例:

await agent.aiDoubleClick('页面顶部的文件名称');

// 使用 deepThink 功能精确定位元素
await agent.aiDoubleClick('页面顶部的文件名称', { deepThink: true });

agent.aiRightClick()

仅在 web 页面中可用,在 Android 下不可用

右键点击某个元素。请注意,Midscene 在右键点击后无法与浏览器原生上下文菜单交互。这个接口通常用于已经监听了右键点击事件的元素。

  • 类型
function aiRightClick(locate: string | Object, options?: Object): Promise<void>;
  • 参数:

    • locate: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • options?: Object - 可选,一个配置对象,包含:
      • deepThink?: boolean - 是否开启深度思考。如果为 true,Midscene 会调用 AI 模型两次以精确定位元素,从而提升准确性。默认值为 false。对于新一代模型(如 Qwen3 / Doubao 1.6 / Gemini 3),带来的收益不明显。
      • xpath?: string - 目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
      • cacheable?: boolean - 当启用 缓存功能 时,是否允许缓存当前 API 调用结果。默认值为 true
  • 返回值:

    • Promise<void>
  • 示例:

await agent.aiRightClick('页面顶部的文件名称');

// 使用 deepThink 功能精确定位元素
await agent.aiRightClick('页面顶部的文件名称', { deepThink: true });
关于

deepThink (深度思考)特性

deepThink 会让 Midscene 发起两次定位请求以提升准确性。这在目标元素面积较小、难以和周围元素区分时非常有用。对于新一代模型(如 Qwen3 / Doubao 1.6 / Gemini 3),带来的收益不明显,建议按需开启。

注意:aiAct() 中的 deepThink 与元素定位方法中的 deepThink 不同。在 aiAct() 中,它控制的是规划阶段的思考策略。详情参阅说明

数据提取

agent.aiAsk()

使用此方法,你可以针对当前页面,直接向 AI 模型发起提问,并获得字符串形式的回答。

  • 类型
function aiAsk(prompt: string | Object, options?: Object): Promise<string>;
  • 参数:

    • prompt: string | Object - 用自然语言描述的询问内容,或使用图片作为提示词
    • options?: Object - 可选,一个配置对象,包含:
      • domIncluded?: boolean | 'visible-only' - 是否向模型发送精简后的 DOM 信息,一般用于提取 UI 中不可见的属性,比如图片的链接。如果设置为 'visible-only',则只发送可见的元素。默认值为 false。
      • screenshotIncluded?: boolean - 是否向模型发送截图。默认值为 true。
  • 返回值:

    • 返回一个 Promise。返回 AI 模型的回答。
  • 示例:

const result = await agent.aiAsk('当前页面的应该怎么进行测试?');
console.log(result); // 输出 AI 模型的回答

除了 aiAsk 方法,你还可以使用 aiQuery 方法,直接从 UI 提取结构化的数据。

agent.aiQuery()

使用此方法,你可以直接从 UI 提取结构化的数据。只需在 dataDemand 中描述期望的数据格式(如字符串、数字、JSON、数组等),Midscene 即返回相应结果。

  • 类型
function aiQuery<T>(dataDemand: string | Object, options?: Object): Promise<T>;
  • 参数:

    • dataDemand: T: 描述预期的返回值和格式。
    • options?: Object - 可选,一个配置对象,包含:
      • domIncluded?: boolean | 'visible-only' - 是否向模型发送精简后的 DOM 信息,一般用于提取 UI 中不可见的属性,比如图片的链接。如果设置为 'visible-only',则只发送可见的元素。默认值为 false。
      • screenshotIncluded?: boolean - 是否向模型发送截图。默认值为 true。
  • 返回值:

    • 返回值可以是任何合法的基本类型,比如字符串、数字、JSON、数组等。
    • 你只需在 dataDemand 中描述它,Midscene 就会给你满足格式的返回。
  • 示例:

const dataA = await agent.aiQuery({
  time: '左上角展示的日期和时间,string',
  userInfo: '用户信息,{name: string}',
  tableFields: '表格的字段名,string[]',
  tableDataRecord: '表格中的数据记录,{id: string, [fieldName]: string}[]',
});

// 你也可以用纯字符串描述预期的返回值格式:

// dataB 将是一个字符串数组
const dataB = await agent.aiQuery('string[],列表中的任务名称');

// dataC 将是一个包含对象的数组
const dataC = await agent.aiQuery(
  '{name: string, age: string}[], 表格中的数据记录',
);

// 使用 domIncluded 功能提取 UI 中不可见的属性
const dataD = await agent.aiQuery(
  '{name: string, age: string, avatarUrl: string}[], 表格中的数据记录',
  { domIncluded: true },
);

此外,我们还提供了 aiBoolean(), aiNumber(), aiString() 三个便捷方法,用于直接提取布尔值、数字和字符串。

agent.aiBoolean()

从 UI 中提取一个布尔值。

  • 类型
function aiBoolean(prompt: string | Object, options?: Object): Promise<boolean>;
  • 参数:

    • prompt: string - 用自然语言描述的期望值,或使用图片作为提示词
    • options?: Object - 可选,一个配置对象,包含:
      • domIncluded?: boolean | 'visible-only' - 是否向模型发送精简后的 DOM 信息,一般用于提取 UI 中不可见的属性,比如图片的链接。如果设置为 'visible-only',则只发送可见的元素。默认值为 false。
      • screenshotIncluded?: boolean - 是否向模型发送截图。默认值为 true。
  • 返回值:

    • 返回一个 Promise。当 AI 返回结果时解析为布尔值。
  • 示例:

const boolA = await agent.aiBoolean('是否存在登录对话框');

// 使用 domIncluded 功能提取 UI 中不可见的属性
const boolB = await agent.aiBoolean('忘记密码按钮是否存在链接', {
  domIncluded: true,
});

agent.aiNumber()

从 UI 中提取一个数字。

  • 类型
function aiNumber(prompt: string | Object, options?: Object): Promise<number>;
  • 参数:

    • prompt: string | Object - 用自然语言描述的期望值,或使用图片作为提示词
    • options?: Object - 可选,一个配置对象,包含:
      • domIncluded?: boolean | 'visible-only' - 是否向模型发送精简后的 DOM 信息,一般用于提取 UI 中不可见的属性,比如图片的链接。如果设置为 'visible-only',则只发送可见的元素。默认值为 false。
      • screenshotIncluded?: boolean - 是否向模型发送截图。默认值为 true。
  • 返回值:

    • 返回一个 Promise。当 AI 返回结果时解析为数字。
  • 示例:

const numberA = await agent.aiNumber('账户剩余的积分');

// 使用 domIncluded 功能提取 UI 中不可见的属性
const numberB = await agent.aiNumber('账户剩余的积分元素的 value 值', {
  domIncluded: true,
});

agent.aiString()

从 UI 中提取一个字符串。

  • 类型
function aiString(prompt: string | Object, options?: Object): Promise<string>;
  • 参数:

    • prompt: string | Object - 用自然语言描述的期望值,或使用图片作为提示词
    • options?: Object - 可选,一个配置对象,包含:
      • domIncluded?: boolean | 'visible-only' - 是否向模型发送精简后的 DOM 信息,一般用于提取 UI 中不可见的属性,比如图片的链接。如果设置为 'visible-only',则只发送可见的元素。默认值为 false。
      • screenshotIncluded?: boolean - 是否向模型发送截图。默认值为 true。
  • 返回值:

    • 返回一个 Promise。当 AI 返回结果时解析为字符串。
  • 示例:

const stringA = await agent.aiString('当前列表的第一条记录的名称');

// 使用 domIncluded 功能提取 UI 中不可见的属性
const stringB = await agent.aiString('当前列表的第一条记录的跳转链接', {
  domIncluded: true,
});

更多方法

agent.aiAssert()

通过自然语言描述一个断言条件,让 AI 判断该条件是否为真。当条件不满足时,SDK 会抛出错误,并在错误信息中追加 AI 返回的详细原因。

  • 类型
function aiAssert(
  assertion: string | Object, 
  errorMsg?: string, 
  options?: Object
): Promise<void>;
  • 参数:

    • assertion: string | Object - 用自然语言描述的断言条件,或使用图片作为提示词
    • errorMsg?: string - 当断言失败时附加的可选错误提示信息。
    • options?: Object - 可选,一个配置对象,包含:
      • domIncluded?: boolean | 'visible-only' - 是否向模型发送精简后的 DOM 信息,一般用于提取 UI 中不可见的属性,比如图片的链接。如果设置为 'visible-only',则只发送可见的元素。默认值为 false。
      • screenshotIncluded?: boolean - 是否向模型发送截图。默认值为 true。
  • 返回值:

    • 返回一个 Promise。当断言成功时解析为 void;若断言失败,则抛出一个错误,错误信息包含 errorMsg 以及 AI 生成的原因。
  • 示例:

await agent.aiAssert('"Sauce Labs Onesie" 的价格是 7.99');
Tip

断言在测试脚本中非常重要。为了降低因 AI 幻觉导致错误断言的风险(例如遗漏错误),你也可以使用 .aiQuery 加上常规的 JavaScript 断言来替代 .aiAssert

例如,你可以这样替代上面的断言代码:

const items = await agent.aiQuery(
  '"{name: string, price: number}[], 返回商品名称和价格列表',
);
const onesieItem = items.find((item) => item.name === 'Sauce Labs Onesie');
expect(onesieItem).toBeTruthy();
expect(onesieItem.price).toBe(7.99);

agent.aiLocate()

通过自然语言描述一个元素的定位。

  • 类型
function aiLocate(
  locate: string | Object,
  options?: Object,
): Promise<{
  rect: {
    left: number;
    top: number;
    width: number;
    height: number;
  };
  center: [number, number];
  scale: number; // device pixel ratio
}>;
  • 参数:

    • locate: string | Object - 用自然语言描述的元素定位,或使用图片作为提示词
    • options?: Object - 可选,一个配置对象,包含:
      • deepThink?: boolean - 是否开启深度思考。如果为 true,Midscene 会调用 AI 模型两次以精确定位元素,从而提升准确性。默认值为 false。对于新一代模型(如 Qwen3 / Doubao 1.6 / Gemini 3),带来的收益不明显。
      • xpath?: string - 目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
      • cacheable?: boolean - 当启用 缓存功能 时,是否允许缓存当前 API 调用结果。默认值为 true
  • 返回值:

    • 返回一个 Promise。当元素定位成功时解析为元素定位信息。
  • 示例:

const locateInfo = await agent.aiLocate('页面顶部的登录按钮');
console.log(locateInfo);

agent.aiWaitFor()

等待某个条件达成。考虑到 AI 服务的成本,检查间隔不会超过 checkIntervalMs 毫秒。

  • 类型
function aiWaitFor(
  assertion: string,
  options?: {
    timeoutMs?: number;
    checkIntervalMs?: number;
  },
): Promise<void>;
  • 参数:

    • assertion: string - 用自然语言描述的断言条件
    • options?: object - 可选的配置对象
      • timeoutMs?: number - 超时时间(毫秒,默认为 15000)。每轮检查开始时都会记录时间,只要该时间点仍在超时窗口内,就会进入下一轮检查;否则视为超时
      • checkIntervalMs?: number - 检查间隔(毫秒),默认为 3000
  • 返回值:

    • 返回一个 Promise。当断言成功时解析为 void;若超时,则抛出错误。
  • 示例:

// 基本用法
await agent.aiWaitFor('界面上至少有一个耳机的信息');

// 使用自定义配置
await agent.aiWaitFor('购物车图标显示数量为 2', {
  timeoutMs: 30000, // 等待 30 秒
  checkIntervalMs: 5000, // 每 5 秒检查一次
});
Tip

考虑到 AI 服务的时间消耗,.aiWaitFor 并不是一个特别高效的方法。使用一个普通的 sleep 可能是替代 waitFor 的另一种方式。

agent.runYaml()

执行一个 YAML 格式的自动化脚本。脚本中的 tasks 部分会被解析和执行,并返回所有 .aiQuery 调用的结果。

  • 类型
function runYaml(yamlScriptContent: string): Promise<{ result: any }>;
  • 参数:

    • yamlScriptContent: string - YAML 格式的脚本内容
  • 返回值:

    • 返回一个包含 result 属性的对象,其中包含所有 aiQuery 调用的结果
  • 示例:

const { result } = await agent.runYaml(`
tasks:
  - name: search weather
    flow:
      - ai: input 'weather today' in input box, click search button
      - sleep: 3000

  - name: query weather
    flow:
      - aiQuery: "the result shows the weather info, {description: string}"
`);
console.log(result);
Tip

更多关于 YAML 脚本的信息,请参考 Automate with Scripts in YAML

agent.setAIActContext()

设置在调用 agent.aiAct()agent.ai() 时,发送给 AI 模型的背景知识。这个设置会覆盖之前的设置。

对于即时操作类型的 API,比如 aiTap(),这个设置不会生效。

  • 类型
function setAIActContext(aiActContext: string): void;
  • 参数:

    • aiActContext: string - 要发送给 AI 模型的背景知识。aiActionContext 旧参数名依然可用。
  • 示例:

await agent.setAIActContext('如果 “使用cookie” 对话框存在,先关闭它');
Note

agent.setAIActionContext() 已被弃用,请改用 agent.setAIActContext()。弃用的方法仍作为兼容别名保留。

agent.evaluateJavaScript()

仅在 web 页面中可用,在 Android 下不可用

这个方法允许你在 web 页面上下文中执行一段 JavaScript 代码,并返回执行结果。

  • 类型
function evaluateJavaScript(script: string): Promise<any>;
  • 参数:

    • script: string - 要执行的 JavaScript 代码。
  • 返回值:

    • 返回执行结果。
  • 示例:

const result = await agent.evaluateJavaScript('document.title');
console.log(result);

agent.recordToReport()

在报告文件中记录当前截图,并添加描述。

  • 类型
function recordToReport(title?: string, options?: Object): Promise<void>;
  • 参数:

    • title?: string - 可选,截图的标题,如果未提供,则标题为 'untitled'。
    • options?: Object - 可选,一个配置对象,包含:
      • content?: string - 截图的描述。
  • 返回值:

    • Promise<void>
  • 示例:

await agent.recordToReport('登录页面', {
  content: '用户 A',
});

agent.freezePageContext()

冻结当前页面上下文,使后续所有的操作都复用同一个页面快照,避免多次重复获取页面状态。在执行大量并发操作时,它可以显著提升性能。

一些注意点:

  • 通常情况下,你不需要使用这个方法,除非你确定“页面状态获取”是脚本性能瓶颈。
  • 需要及时调用 agent.unfreezePageContext() 来恢复实时页面状态。
  • 不要在交互类操作中使用这个方法,它会让 AI 模型无法感知到页面的最新状态,产生令人困惑的错误。
  • 类型
function freezePageContext(): Promise<void>;
  • 返回值:

    • Promise<void>
  • 示例:

// 冻结页面上下文,确保多个操作看到相同的页面状态
await agent.freezePageContext();

// 执行一些操作...
const results = await Promise.all([
  await agent.aiQuery('Username input box value'),
  await agent.aiQuery('Password input box value'),
  await agent.aiLocate('Login button'),
]);
console.log(results);

// 解冻页面上下文
await agent.unfreezePageContext();
Tip

在报告中,使用冻结上下文的操作会在 Insight tab 中显示 🧊 图标。

agent.unfreezePageContext()

解冻页面上下文,恢复使用实时的页面状态。

  • 类型
function unfreezePageContext(): Promise<void>;
  • 返回值:

    • Promise<void>

agent._unstableLogContent()

从报告文件中获取日志内容。日志内容的结构可能会在未来发生变化。

  • 类型
function _unstableLogContent(): Object;
  • 返回值:

    • 返回一个对象,包含日志内容。
  • 示例:

const logContent = agent._unstableLogContent();
console.log(logContent);

属性

.reportFile

报告文件的路径。

在运行时设置环境变量(已弃用)

已弃用,请使用 modelConfig 参数代替。

通过 overrideAIConfig 方法在运行时设置全局环境变量。

import { overrideAIConfig } from '@midscene/web/puppeteer'; // 或其他的 Agent

overrideAIConfig({
  MIDSCENE_MODEL_BASE_URL: '...', // 推荐使用新的变量名
  MIDSCENE_MODEL_API_KEY: '...', // 推荐使用新的变量名
  MIDSCENE_MODEL_NAME: '...',

  // 旧的变量名仍然兼容:
  // OPENAI_BASE_URL: '...',
  // OPENAI_API_KEY: '...',
});

使用图片作为提示词

你可以在提示词中使用图片作为补充,来描述无法通过自然语言表达的内容。

使用图片作为提示词时,提示词的参数格式如下:

{
  // 提示词文本,其中可提及需要使用的图片
  prompt: string,
  // 提示词中提到的图片
  images?: {
    // 图片名称,需要和提示词文本中提到的图片名称对应
    name: string,
    // 图片 url,可以是本地图片路径、Base64 字符串,或者图片的 http 链接
    url: string
  }[]
  // 开启该选项后,http 格式的图片链接会被转化为 Base64 编码发送给大模型,适用于图片链接不是公开可访问的情况。
  convertHttpImage2Base64?: boolean
}
  • 示例一:使用图片描述点击位置
await agent.aiTap({
  prompt: '指定 logo',
  images: [
    {
      name: '指定 logo',
      url: 'https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png',
    },
  ],
});
  • 示例二:使用图片进行页面断言
await agent.aiAssert({
  prompt: '页面上是否存在指定 logo',
  images: [
    {
      name: '指定 logo',
      url: 'https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png',
    },
  ],
});

图片尺寸的注意事项

在提示词中使用图片时,可能需要关注模型提供商对图片体积和尺寸的要求,过大(比如超过 10M)或过小(比如小于 10 像素)的图片都有可能导致模型调用时出现报错,具体的限制请以你所使用模型提供商的文档为准。

报告合并工具

在运行多个自动化工作流时,每个 agent 都会生成独立的报告文件。ReportMergingTool 提供了将多个自动化报告合并为单个报告的能力,便于统一查看和管理自动化结果。

使用场景

  • 在自动化套件中运行多个工作流,希望生成一个统一的报告
  • 跨平台自动化(如 Web 和 Android)需要合并不同平台的自动化结果
  • CI/CD 流程中需要生成汇总的自动化报告

new ReportMergingTool()

创建一个报告合并工具实例。

  • 示例:
import { ReportMergingTool } from '@midscene/core/report';

const reportMergingTool = new ReportMergingTool();

.append()

将自动化报告添加到待合并列表中。通常在每个自动化工作流结束后调用此方法。

  • 类型
function append(reportInfo: ReportFileWithAttributes): void;
  • 参数:

    • reportInfo: ReportFileWithAttributes - 报告信息对象,包含:
      • reportFilePath: string - 报告文件的路径,通常是 agent.reportFile
      • reportAttributes: object - 报告属性
        • testId: string - 自动化工作流的唯一标识符
        • testTitle: string - 自动化工作流标题
        • testDescription: string - 自动化工作流描述
        • testDuration: number - 自动化工作流执行时长(毫秒)
        • testStatus: 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interrupted' - 自动化状态
  • 返回值:

    • void
  • 示例:

// 在 afterEach 钩子中添加报告
afterEach((ctx) => {
  let workflowStatus = 'passed';
  if (ctx.task.result?.state === 'fail') {
    workflowStatus = 'failed';
  }

  reportMergingTool.append({
    reportFilePath: agent.reportFile as string,
    reportAttributes: {
      testId: ctx.task.name,
      testTitle: ctx.task.name,
      testDescription: '自动化工作流描述',
      testDuration: Date.now() - startTime,
      testStatus: workflowStatus,
    },
  });
});

.mergeReports()

执行报告合并操作,将所有添加的报告合并为一个 HTML 文件。

  • 类型
function mergeReports(
  reportFileName?: 'AUTO' | string,
  opts?: {
    rmOriginalReports?: boolean;
    overwrite?: boolean;
  },
): string | null;
  • 参数:

    • reportFileName?: 'AUTO' | string - 合并后的报告文件名
      • 默认为 'AUTO',自动生成文件名
      • 可以指定自定义文件名(不需要 .html 后缀)
    • opts?: object - 可选配置对象
      • rmOriginalReports?: boolean - 是否删除原始报告文件,默认为 false
      • overwrite?: boolean - 如果目标文件已存在是否覆盖,默认为 false
  • 返回值:

    • 成功时返回合并后的报告文件路径
    • 如果报告数量不足(少于 2 个),返回 null
  • 示例:

// 基本用法 - 使用自动生成的文件名
afterAll(() => {
  reportMergingTool.mergeReports();
});

// 指定自定义文件名
afterAll(() => {
  reportMergingTool.mergeReports('my-automation-report');
});

// 合并后删除原始报告
afterAll(() => {
  reportMergingTool.mergeReports('my-automation-report', {
    rmOriginalReports: true,
  });
});

// 覆盖已存在的报告文件
afterAll(() => {
  reportMergingTool.mergeReports('my-automation-report', {
    overwrite: true,
  });
});

.clear()

清空待合并的报告列表。如果需要在同一个实例中进行多次合并操作,可以使用此方法清空之前的报告列表。

  • 类型
function clear(): void;
  • 返回值:

    • void
  • 示例:

reportMergingTool.mergeReports('first-batch');
reportMergingTool.clear(); // 清空列表
// 继续添加新的报告...

完整示例

以下是在 Vitest 框架中使用 ReportMergingTool 的完整示例:

import { describe, it, beforeEach, afterEach, afterAll } from 'vitest';
import { AndroidAgent, AndroidDevice } from '@midscene/android';
import { ReportMergingTool } from '@midscene/core/report';

describe('Android 设置自动化', () => {
  let device: AndroidDevice;
  let agent: AndroidAgent;
  let startTime: number;
  const reportMergingTool = new ReportMergingTool();

  beforeEach((ctx) => {
    startTime = performance.now();
    agent = new AndroidAgent(device, {
      groupName: ctx.task.name,
    });
  });

  afterEach((ctx) => {
    // 确定自动化状态
    let workflowStatus = 'passed';
    if (ctx.task.result?.state === 'pass') {
      workflowStatus = 'passed';
    } else if (ctx.task.result?.state === 'skip') {
      workflowStatus = 'skipped';
    } else if (ctx.task.result?.errors?.[0]?.message.includes('timed out')) {
      workflowStatus = 'timedOut';
    } else {
      workflowStatus = 'failed';
    }

    // 添加报告到合并列表
    reportMergingTool.append({
      reportFilePath: agent.reportFile as string,
      reportAttributes: {
        testId: ctx.task.name,
        testTitle: ctx.task.name,
        testDescription: '自动化工作流描述',
        testDuration: (Date.now() - ctx.task.result?.startTime!) | 0,
        testStatus: workflowStatus,
      },
    });
  });

  afterAll(() => {
    // 合并所有自动化报告
    reportMergingTool.mergeReports('android-settings-automation-report');
  });

  it('切换 WLAN', async () => {
    await agent.aiAct('找到并进入 WLAN 设置');
    await agent.aiAct('切换 WLAN 状态一次');
  });

  it('切换蓝牙', async () => {
    await agent.aiAct('找到并进入蓝牙设置');
    await agent.aiAct('切换蓝牙状态一次');
  });
});
Tip

合并后的报告文件会保存在 midscene_run/report 目录下。你可以使用浏览器打开合并后的 HTML 文件查看所有自动化工作流的执行情况。