跳到正文

DoAnything ​

DoAnything 是开放式浏览器任务 API,也是 WebAgent 的主要执行入口。你给出自然语言目标,agent 在真实浏览器里自主决定如何打开页面、搜索、点击、填写和读取结果,并把执行过程和最终结果回传。本页先介绍它解决的问题和核心能力,再给出当前调用方式。

它解决什么问题 ​

  • 步骤写不死的网页任务:目标跨多个页面、路径随页面结构变化,传统脚本一改版就断。DoAnything 由 agent 在运行时规划和调整执行路径,你只维护目标,不维护选择器。
  • 登录后的操作没有 API:很多后台系统和会员页面只有网页入口。DoAnything 在受控浏览器里复用 Profiles 的登录态,直接在页面上完成读取和操作。
  • 关键动作需要人参与:执行中的确认请求以 interaction 事件回传,人确认后任务继续,不必在"全自动"和"全人工"之间二选一。
  • 执行过程要可观察、可追溯:每一步通过 SSE 事件流回传,可开启截图留证;失败的 run 可以取消、重连或在同一浏览器上下文继续。

核心能力 ​

能力说明
自主执行一句 instruction 创建 run,agent 自主规划浏览器动作序列
真实浏览器打开、搜索、点击、填写、读取都发生在受控的真实浏览器中
上下文复用session 复用浏览器上下文,profileId 复用登录态
事件流SSE 回传 progress、message、interaction、screenshot、done
人工确认interaction 事件携带确认请求,通过 interactionHandle 响应
过程留证capture.screenshots 开启截图,事件流保留执行轨迹
运行控制limits.maxDurationMinutes 设时长上限;支持取消、暂停、恢复和重连

典型场景 ​

什么时候用 ​

  • 目标跨多个页面,步骤不适合写死。
  • 需要复用登录态、浏览器上下文或人工确认。
  • 结果形态不固定,接受 agent 根据目标组织输出。

需要固定结构的搜索结果或研究报告时,使用 WebSearch 或 DeepResearch;需要按计划长期盯守页面变化时,使用 Track。

当前调用方式 ​

Node.js / TypeScript ​

ts
const { token } = (await qoni.delegateToken({
  user: { id: process.env.QONI_USER_ID! },
  products: ["doAnything"],
})).data;

const run = await qoni.doAnything.run({
  token,
  prompt: "打开 Hacker News,列出首页前五条故事的标题和链接。",
  capture: { screenshots: true },
  limits: { maxDurationMinutes: 10 },
  profileId: "prof_alice",
});

const result = await run.wait();
console.log(result.status, result.output);

run() 返回 RunHandle,使用 run.id 取 ID;不要按旧示例使用 run["run_id"]、client.sessions 或 runAsync()。

原生 HTTP ​

http
POST /api/v1/projects/{pid}/do_anything/runs
Authorization: Bearer wa_...
Content-Type: application/json

{
  "instructions": "打开 Hacker News,列出首页前五条故事。",
  "max_duration_minutes": 10,
  "profile_id": "prof_alice"
}

不传 session_id 时,后端为本次 run 创建 session;传入已有 session_id 可以在同一浏览器上下文继续执行。创建响应是 202 和 run envelope。

生命周期 ​

当前后端的 run 状态是:pending、running、awaiting_input、succeeded、failed、canceled。terminal_reason 可能是 done、failed、canceled 或 expired。Node SDK 用 wait() 等待终态,用 status() 刷新状态,用 cancel() 取消。

事件流 ​

http
GET /api/v1/projects/{pid}/do_anything/runs/{run_id}/events
Authorization: Bearer wa_...

Node SDK 把事件归一为 progress、message、interaction、screenshot 和 done;需要底层 wire 事件时通过 event.raw.event 查看。断线后带 Last-Event-ID 重连。

ts
for await (const event of run.events()) {
  switch (event.type) {
    case "progress":
    case "message":
      console.log(event.data);
      break;
    case "interaction": {
      const interaction = run.interactionHandle(event.data);
      if (interaction.can("confirm")) await interaction.confirm();
      break;
    }
    case "done":
      console.log("finished", event.data);
      break;
  }
}

继续执行与重连 ​

ts
const next = await qoni.doAnything.run({
  token,
  prompt: "继续打开第一条链接,整理评论区的主要观点。",
  session: run.sessionRef,
});

const reattached = await qoni.doAnything.attach(run.id, { token });

同一 session 的前一条 run 未结束时,后端会拒绝并发 follow-up;先等待终态再继续。

原生 HTTP 的控制端点 ​

单 run 路径还提供 GET .../{run_id}、POST .../{run_id}/cancel、POST .../{run_id}/intervene、POST .../{run_id}/messages、GET .../{run_id}/screenshots、POST .../{run_id}/pause 和 POST .../{run_id}/resume。这些端点的请求体以 OpenAPI 为准;Node 高层 SDK 不把它们伪装成不存在的 client.messages 方法。