# Wiki Documentation for https://github.com/browserbase/stagehand

Generated on: 2026-05-10 12:00:15 UTC

## Table of Contents

- [Stagehand 简介](#introduction)
- [快速开始](#quickstart)
- [系统架构总览](#architecture-overview)
- [act() 操作执行](#act-api)
- [extract() 数据提取](#extract-api)
- [observe() 页面观察](#observe-api)
- [Agent 代理系统](#agent-system)
- [Handler 处理系统](#handler-system)
- [DOM 与无障碍树](#dom-accessibility)
- [Deep Locator 深层定位器](#deep-locator)

<a id='introduction'></a>

## Stagehand 简介

### Related Pages

Related topics: [快速开始](#quickstart), [系统架构总览](#architecture-overview)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
- [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)
- [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)
</details>

# Stagehand 简介

Stagehand 是一个基于浏览器自动化框架的工具，通过命令行接口（CLI）提供对浏览器的精细控制能力。该项目由 Browserbase 开发，支持本地和远程两种运行模式，能够执行页面导航、元素交互、网络请求捕获、截图等多种浏览器自动化任务。

## 核心架构

Stagehand 采用客户端-守护进程（Client-Daemon）架构设计，CLI 作为客户端与守护进程通信，守护进程负责实际管理浏览器实例。

```mermaid
graph TD
    A[CLI Client] --> B[Socket Communication]
    B --> C[Daemon Process]
    C --> D[Browser Instance]
    C --> E[Local CDP Discovery]
    D --> F[Network Capture]
    E --> C
```

### 守护进程基础设施

守护进程管理依赖 Socket 文件进行进程间通信，关键路径配置如下：

```typescript
const SOCKET_DIR = os.tmpdir();

function getSocketPath(session: string): string {
  return path.join(SOCKET_DIR, `browse-${session}.sock`);
}

function getLockPath(session: string): string {
  return path.join(SOCKET_DIR, `browse-${session}.lock`);
}
```

守护进程实现了基于文件锁的并发控制机制，使用 `O_EXCL` 标志确保原子性文件创建，防止竞争条件：

```typescript
async function acquireLock(
  session: string,
  timeoutMs: number = 10000,
): Promise<boolean> {
  const lockPath = getLockPath(session);
  // O_EXCL ensures atomic creation - fails if file exists
  const handle = await fs.open(lockPath, "wx");
  await handle.write(String(process.pid));
  await handle.close();
  return true;
}
```

Sources: [packages/cli/src/index.ts:1-50]()

## CLI 命令系统

Stagehand CLI 提供丰富的命令集，覆盖浏览器自动化的各个方面。

### 导航与页面操作

| 命令 | 说明 | 关键选项 |
|------|------|----------|
| `open <url>` | 导航到指定 URL | `--wait`, `--timeout`, `--context-id`, `--persist` |
| `goto <url>` | `open` 的别名 | 同上 |
| `pages` | 列出所有打开的页面 | - |
| `newpage [url]` | 创建新页面/标签页 | - |

导航命令支持多种等待状态：

- `load`（默认）
- `domcontentloaded`
- `networkidle`

```typescript
program
  .command("open <url>")
  .alias("goto")
  .description("Navigate to URL")
  .option(
    "--wait <state>",
    "Wait state: load, domcontentloaded, networkidle",
    "load",
  )
  .option("-t, --timeout <ms>", "Navigation timeout in milliseconds", "30000")
```

Sources: [packages/cli/src/index.ts:80-130]()

### 元素交互

元素操作命令支持通过选择器精确定位和操作 DOM 元素：

| 命令 | 说明 | 选项 |
|------|------|------|
| `click <selector>` | 点击元素 | `--button`, `--delay`, `--xpath` |
| `dblclick <selector>` | 双击元素 | `--button`, `--delay` |
| `fill <selector> <value>` | 填充输入框 | `--no-press-enter` |
| `select <selector> <values...>` | 选择下拉选项 | - |
| `hover <x> <y>` | 悬停在坐标位置 | `--xpath` |
| `scroll <x> <y> <deltaX> <deltaY>` | 滚动操作 | `--xpath` |
| `drag <fromX> <fromY> <toX> <toY>` | 拖拽操作 | `--delay`, `--xpath` |

```typescript
program
  .command("fill <selector> <value>")
  .description("Fill input element (presses Enter by default)")
  .option("--no-press-enter", "Don't press Enter after filling")
  .action(async (selector: string, value: string, cmdOpts) => {
    const pressEnter = cmdOpts.pressEnter !== false;
    const result = await runCommand("fill", [selector, value, { pressEnter }]);
  });
```

Sources: [packages/cli/src/index.ts:150-200]()

### 键盘与输入

| 命令 | 说明 | 选项 |
|------|------|------|
| `type <text>` | 输入文本 | `-d, --delay`, `--mistakes` |
| `press <key>` | 按下按键 | - |
| `key <key>` | `press` 的别名 | - |

```typescript
program
  .command("type <text>")
  .description("Type text")
  .option("-d, --delay <ms>", "Delay between keystrokes")
  .option("--mistakes", "Enable human-like typing with mistakes")
```

### 页面信息获取

| 命令 | 说明 | 获取类型 |
|------|------|----------|
| `get <what> [selector]` | 获取页面信息 | `url`, `title`, `text`, `html`, `markdown`, `value`, `box`, `visible`, `checked` |

```typescript
program
  .command("get <what> [selector]")
  .description(
    "Get page info: url, title, text, html, markdown, value, box, visible, checked",
  )
```

### 截图功能

截图命令支持多种输出格式和裁剪选项：

```typescript
program
  .command("screenshot [path]")
  .description("Take screenshot")
  .option("-f, --full-page", "Full page screenshot")
  .option("-t, --type <type>", "Image type: png, jpeg", "png")
  .option("-q, --quality <n>", "JPEG quality (0-100)")
  .option("--clip <json>", "Clip region as JSON")
  .option("--no-animations", "Disable animations")
  .option("--hide-caret", "Hide text caret")
```

Sources: [packages/cli/src/index.ts:220-280]()

### 可访问性快照

获取页面的可访问性树快照：

```typescript
program
  .command("snapshot")
  .description("Get accessibility tree snapshot")
  .option("-c, --compact", "Output tree only (no xpath map)")
```

快照返回结构包含：
- `tree`: 格式化的可访问性树
- `xpathMap`: 元素到 XPath 的映射
- `urlMap`: URL 映射

Sources: [packages/cli/src/index.ts:290-310]()

### 等待与状态检查

| 命令 | 说明 | 状态值 |
|------|------|--------|
| `wait <type> [arg]` | 等待条件 | `load`, `selector`, `timeout` |
| `is <check> <selector>` | 检查元素状态 | `visible`, `checked` |

```typescript
program
  .command("wait <type> [arg]")
  .description("Wait for: load, selector, timeout")
  .option("-t, --timeout <ms>", "Timeout", "30000")
  .option("-s, --state <state>", "Element state: visible, hidden, attached, detached", "visible")
```

Sources: [packages/cli/src/index.ts:50-80]()

### 视口控制

```typescript
program
  .command("viewport <width> <height>")
  .description("Set viewport size")
  .option("-s, --scale <n>", "Device scale factor", "1")
```

## 本地浏览器策略

Stagehand 支持多种本地浏览器启动策略，可通过配置灵活选择。

### 策略类型

| 策略 | 说明 | 适用场景 |
|------|------|----------|
| `isolated` | 启动独立的 Chromium 实例 | 完全隔离的自动化任务 |
| `cdp` | 连接到指定的 Chrome DevTools Protocol 端点 | 复用已有浏览器会话 |
| `auto` | 自动检测本地浏览器，无则启动隔离实例 | 通用场景 |

```typescript
export async function resolveLocalStrategy({
  localConfig,
  headless,
  defaultViewport,
  discoverLocalCdp,
  resolveWsTarget,
}: ResolveLocalStrategyOptions): Promise<ResolvedLocalStrategy> {
  if (localConfig.strategy === "isolated") {
    return {
      localLaunchOptions: { headless, viewport: defaultViewport },
      localInfo: { localSource: "isolated" },
    };
  }

  if (localConfig.strategy === "cdp") {
    const cdpUrl = await resolveWsTarget(localConfig.cdpTarget);
    return {
      localLaunchOptions: { cdpUrl },
      localInfo: { localSource: "attached-explicit", resolvedCdpUrl: cdpUrl },
    };
  }
}
```

Sources: [packages/cli/src/local-strategy.ts:1-80]()

### CDP 自动发现

系统支持自动发现本地运行的 Chrome 实例：

```typescript
async function probeFallbackPort(port: number): Promise<string | null> {
  const jsonVersionUrl = await probeJsonVersion(port);
  if (jsonVersionUrl) {
    return jsonVersionUrl;
  }
  // WebSocket fallback...
}
```

Sources: [packages/cli/src/local-cdp-discovery.ts:1-50]()

### 本地模式提示

根据不同的启动策略，系统会提供相应的使用提示：

```typescript
const ISOLATED_MODE_HINT = "Hint: Run `browse env local --auto-connect` to reuse your local browsing credentials and cookies.";
const ATTACHED_EXISTING_HINT = "Hint: Run `browse env local` without `--auto-connect` to switch back to an isolated Chromium browser.";
```

## 网络捕获功能

Stagehand 提供完整的网络请求捕获和持久化能力。

### 数据模型

```typescript
interface PendingRequest {
  id: string;
  timestamp: string;
  method: string;
  url: string;
  headers: Record<string, string>;
  body: string | null;
  resourceType: string;
}
```

### 文件系统组织

捕获的网络请求按以下结构存储：

```
{networkDir}/
  {counter}-{method}-{domain}-{pathSlug}/
    request.json   # 请求详情
    response.json  # 响应详情
```

文件名生成逻辑：

```typescript
function getRequestDirName(
  counter: number,
  method: string,
  url: string,
): string {
  const parsed = new URL(url);
  const domain = sanitizeForFilename(parsed.hostname, 30);
  const pathPart = parsed.pathname.split("/").filter(Boolean)[0] || "root";
  const pathSlug = sanitizeForFilename(pathPart, 20);
  return `${String(counter).padStart(3, "0")}-${method}-${domain}-${pathSlug}`;
}

function sanitizeForFilename(str: string, maxLen: number = 30): string {
  return str
    .replace(/[^a-zA-Z0-9.-]/g, "-")
    .replace(/-+/g, "-")
    .replace(/^-|-$/g, "")
    .slice(0, maxLen);
}
```

Sources: [packages/cli/src/index.ts:55-100]()

## 全局配置选项

CLI 支持通过全局选项配置会话和行为：

```typescript
interface GlobalOpts {
  ws?: string;              // WebSocket 连接地址
  headless?: boolean;       // 无头模式
  headed?: boolean;         // 有头模式（优先于 headless）
  json?: boolean;           // JSON 输出格式
  session?: string;         // 会话标识
  connect?: string;         // 连接目标
  proxies?: boolean;        // 启用代理（远程模式）
  advancedStealth?: boolean; // 高级隐身模式
  solveCaptchas?: boolean;   // 自动解决验证码
  region?: string;          // 区域设置
  keepAlive?: boolean;       // 保持连接
  sessionTimeout?: number;   // 会话超时时间
  blockAds?: boolean;       // 屏蔽广告
}
```

## 守护进程生命周期管理

### 启动与停止

```typescript
program
  .command("start")
  .description("Start browser daemon")
  .action(async () => {
    if (await isDaemonRunning(session)) {
      console.log(JSON.stringify({ status: "already running", session }));
      return;
    }
    await ensureDaemon(session, isHeadless(opts));
  });

program
  .command("stop")
  .description("Stop browser daemon")
  .option("--force", "Force kill Chrome processes if daemon is unresponsive")
```

### 自动重连机制

CLI 实现了智能重连策略，在连接失败时自动尝试恢复：

```typescript
// Attempt 0: Brief wait and retry
if (attempt === 0) {
  await new Promise((r) => setTimeout(r, 200));
  continue;
}

// Attempt 1: Try to restart daemon without cleanup
if (attempt === 1) {
  await ensureDaemon(session, headless);
  continue;
}

// Final attempt: Full cleanup and restart
await killChromeProcesses(session);
await cleanupStaleFiles(session);
await ensureDaemon(session, headless);
```

Sources: [packages/cli/src/index.ts:350-450]()

## 命令执行流程

```mermaid
sequenceDiagram
    participant CLI
    participant Daemon
    participant Browser
    
    CLI->>Daemon: sendCommand(command, args)
    Daemon->>Browser: Execute action
    Browser-->>Daemon: Result
    Daemon-->>CLI: Return result
    CLI->>CLI: output(result, json?)
```

命令执行的核心逻辑：

```typescript
async function runCommand(
  command: string,
  args: unknown[],
  retries: number = 3,
): Promise<unknown> {
  for (let attempt = 0; attempt < retries; attempt++) {
    try {
      return await sendCommand(session, command, args);
    } catch (err) {
      // Connection error handling...
      if (attempt === 0) {
        await new Promise((r) => setTimeout(r, 200));
        continue;
      }
      await ensureDaemon(session, headless);
    }
  }
}
```

## 快速入门

### 基本导航

```bash
# 打开网页
stagehand open https://example.com

# 带等待状态
stagehand open https://example.com --wait networkidle
```

### 元素交互

```bash
# 点击按钮
stagehand click "#submit-button"

# 填充表单
stagehand fill "input[name=email]" "user@example.com"
stagehand fill "input[name=password]" "secret123"
```

### 页面信息

```bash
# 获取页面标题
stagehand get title

# 获取元素文本
stagehand get text ".article-content"

# 获取可访问性树
stagehand snapshot
```

### 截图

```bash
# 普通截图
stagehand screenshot output.png

# 全页截图
stagehand screenshot full-page.png --full-page

# 指定区域
stagehand screenshot cropped.png --clip '{"x":0,"y":0,"width":800,"height":600}'
```

## 总结

Stagehand 提供了一套完整的浏览器自动化解决方案，具有以下特点：

1. **丰富的命令集**：覆盖导航、交互、信息获取、网络捕获等各方面
2. **灵活的运行模式**：支持本地和远程两种部署方式
3. **智能的策略选择**：可根据需求选择隔离、CDP 或自动模式
4. **可靠的守护进程**：实现了进程锁和自动重连机制
5. **详细的网络捕获**：支持完整的请求/响应持久化

---

<a id='quickstart'></a>

## 快速开始

### Related Pages

Related topics: [Stagehand 简介](#introduction), [系统架构总览](#architecture-overview)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
- [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)
- [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)
- [packages/cli/tsup.config.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/tsup.config.ts)
</details>

# 快速开始

Stagehand 是一个由 Browserbase 开发的浏览器自动化框架，提供 CLI 工具和 Core SDK 两种使用方式，支持本地浏览器和远程 Browserbase 云端浏览器的自动化操作。

## 环境准备

### 前置要求

| 要求 | 说明 |
|------|------|
| Node.js | 版本 20+ |
| Playwright | 用户需自行安装 `playwright` 或 `playwright-core` 包 |
| 系统依赖 | Chrome/Chromium 浏览器（本地模式） |

### 安装步骤

```bash
# 安装核心包
npm install @browserbasehq/stagehand

# 安装 Playwright（必须）
npm install playwright

# 安装浏览器驱动
npx playwright install chromium
```

### 环境变量配置

在项目根目录创建 `.env` 文件，配置必要的环境变量：

```bash
# Browserbase 云端模式必需
BROWSERBASE_API_KEY=your_api_key
BROWSERBASE_PROJECT_ID=your_project_id

# 本地模式可选配置
BROWSERBASE_API_KEY=    # 留空则使用本地模式
```

Sources: [.env.example](https://github.com/browserbase/stagehand/blob/main/.env.example)

## CLI 快速上手

Stagehand CLI 提供丰富的浏览器自动化命令，安装后可通过 `npx stagehand` 或直接安装为全局命令使用。

### 基础命令结构

```bash
# 基本语法
stagehand [options] [command] [arguments]

# 常用全局选项
# --session <name>    指定会话名称
# --headless         以无头模式运行
# --connect <url>    连接到远程 Browserbase 会话
# --json             以 JSON 格式输出结果
```

Sources: [packages/cli/src/index.ts:1-50](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

### 导航与页面操作

```bash
# 打开网页
stagehand open https://example.com

# 等待页面加载完成
stagehand open https://example.com --wait load

# 页面加载超时设置（毫秒）
stagehand open https://example.com --timeout 30000

# 创建新标签页
stagehand newpage https://example.com

# 切换标签页（按索引）
stagehand tab_switch 1

# 关闭标签页
stagehand tab_close
```

Sources: [packages/cli/src/index.ts:200-260](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## 元素交互

### 常见交互命令

| 命令 | 说明 | 示例 |
|------|------|------|
| `fill` | 填写输入框 | `stagehand fill "#search" "关键词"` |
| `select` | 选择下拉选项 | `stagehand select "#dropdown" "选项1"` |
| `click` | 点击元素 | `stagehand click "#submit"` |
| `type` | 模拟键盘输入 | `stagehand type "Hello World"` |
| `press` | 按下特定按键 | `stagehand press "Enter"` |

### 填写表单示例

```bash
# 填写输入框（默认会按 Enter）
stagehand fill "#username" "myuser"
stagehand fill "#password" "mypass"

# 不自动按 Enter
stagehand fill "#input" "value" --no-press-enter

# 输入延迟（模拟人工打字）
stagehand type "Hello" --delay 100

# 启用人工化输入（含随机错误）
stagehand type "Hello" --mistakes
```

Sources: [packages/cli/src/index.ts:150-200](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

### 键盘操作

```bash
# 按下按键
stagehand press Enter
stagehand press Tab
stagehand press Escape
stagehand press "Cmd+A"

# 组合键示例
stagehand press "Cmd+C"
```

Sources: [packages/cli/src/index.ts:140-160](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## 元素状态检查

### 检查命令

```bash
# 检查元素是否可见
stagehand is visible "#submit-button"

# 检查复选框是否选中
stagehand is checked "#agree-checkbox"
```

### 获取页面信息

```bash
# 获取页面 URL
stagehand get url

# 获取页面标题
stagehand get title

# 获取元素文本内容
stagehand get text "#heading"

# 获取元素 HTML
stagehand get html "#container"

# 获取元素 Markdown 格式内容
stagehand get markdown "#article"

# 获取元素值
stagehand get value "#input"

# 获取元素边界框
stagehand get box "#image"

# 获取可见性状态
stagehand get visible "#hidden-element"
```

Sources: [packages/cli/src/index.ts:280-320](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## 等待与同步

### 等待命令

```bash
# 等待页面加载
stagehand wait load

# 等待选择器出现
stagehand wait selector "#content"

# 等待超时（毫秒）
stagehand wait selector "#loading" --timeout 10000

# 等待元素状态
stagehand wait selector "#modal" --state visible
stagehand wait selector "#tooltip" --state hidden
stagehand wait selector "#element" --state attached
```

状态选项：`visible`、`hidden`、`attached`、`detached`

Sources: [packages/cli/src/index.ts:50-80](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## 截图与快照

### 截图功能

```bash
# 基础截图
stagehand screenshot

# 保存到指定路径
stagehand screenshot ./screenshot.png

# 全页面截图
stagehand screenshot ./full-page.png --full-page

# 指定图片格式和质量
stagehand screenshot ./output.jpg --type jpeg --quality 85

# 裁剪区域（JSON 格式）
stagehand screenshot ./cropped.png --clip '{"x":0,"y":0,"width":800,"height":600}'

# 禁用动画和隐藏光标
stagehand screenshot ./clean.png --no-animations --hide-caret
```

Sources: [packages/cli/src/index.ts:340-380](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

### 辅助功能树快照

```bash
# 获取完整快照（含 XPath 映射）
stagehand snapshot

# 紧凑输出（仅树结构）
stagehand snapshot --compact
```

快照输出包含：
- `tree`: 格式化的辅助功能树
- `xpathMap`: 元素到 XPath 的映射
- `urlMap`: URL 引用映射

Sources: [packages/cli/src/index.ts:380-420](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## 坐标操作

### 鼠标操作

```bash
# 悬停到坐标位置
stagehand hover 100 200

# 悬停并返回元素 XPath
stagehand hover 100 200 --xpath

# 滚动页面
stagehand scroll 0 500 0 100

# 拖拽操作
stagehand drag 100 200 300 400
```

Sources: [packages/cli/src/index.ts:220-250](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## 视图控制

```bash
# 设置视口大小
stagehand viewport 1920 1080

# 设置缩放比例
stagehand viewport 1920 1080 --scale 2
```

Sources: [packages/cli/src/index.ts:420-440](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## Daemon 模式

Stagehand 使用守护进程模式管理浏览器实例，支持会话复用。

### 进程管理命令

```bash
# 启动守护进程
stagehand start

# 停止守护进程
stagehand stop

# 强制停止（杀掉 Chrome 进程）
stagehand stop --force

# 检查状态
stagehand status
```

### 会话管理

```bash
# 使用指定会话
stagehand --session my-session open https://example.com

# 远程模式会话超时
stagehand --session my-session --session-timeout 300 open https://example.com
```

Sources: [packages/cli/src/index.ts:450-520](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## 本地模式策略

Stagehand CLI 支持多种本地浏览器模式：

```mermaid
graph TD
    A[开始解析本地策略] --> B{strategy 配置}
    B -->|isolated| C[启动独立 Chromium 实例]
    B -->|cdp| D[连接到指定 CDP 目标]
    B -->|auto| E[自动检测本地浏览器]
    E -->|发现调试端口| F[附加到现有浏览器]
    E -->|未发现| G[回退到隔离模式]
    
    C --> H[返回 localSource: isolated]
    D --> I[返回 localSource: attached-explicit]
    F --> J[返回 localSource: attached-existing]
    G --> K[返回 localSource: isolated-fallback]
```

| 策略 | 说明 | localSource 值 |
|------|------|-----------------|
| `isolated` | 启动独立的 Chromium 实例 | `isolated` |
| `cdp` | 通过 CDP URL 连接到指定浏览器 | `attached-explicit` |
| `auto` | 自动检测或回退 | `attached-existing` / `isolated-fallback` |

Sources: [packages/cli/src/local-strategy.ts:20-80](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)

## CDP 发现机制

本地模式支持自动发现 Chrome DevTools 协议端点：

```mermaid
graph LR
    A[扫描用户数据目录] --> B{读取 DevToolsActivePort}
    B -->|成功| C{检查端口可达性}
    B -->|失败| D[尝试备用端口]
    C -->|可达| E[构建 WebSocket URL]
    C -->|不可达| D
    D --> E
    E --> F[返回 cdpUrl]
```

Sources: [packages/cli/src/local-cdp-discovery.ts:1-60](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)

## 输出格式

### JSON 输出模式

```bash
# 启用 JSON 输出
stagehand get title --json

# 示例输出
{
  "success": true,
  "data": {
    "title": "Example Domain"
  }
}
```

### 基础输出

默认情况下，CLI 以人类可读格式输出结果：

```bash
stagehand get url
# 输出: https://example.com

stagehand snapshot --compact
# 输出: 辅助功能树结构
```

## 网络请求捕获

Stagehand 支持捕获和分析网络请求：

```mermaid
graph TD
    A[请求进入] --> B{网络捕获启用?}
    B -->|否| C[跳过]
    B -->|是| D[记录请求元数据]
    D --> E[等待响应]
    E --> F[写入文件系统]
    F --> G[生成目录结构]
    
    G --> H[request.json]
    G --> I[response.json]
```

请求数据存储结构：
```
<networkDir>/
  └── <counter>-<METHOD>-<domain>-<path>/
      ├── request.json   # 请求详情
      └── response.json  # 响应详情
```

Sources: [packages/cli/src/index.ts:80-150](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## 常见工作流示例

### 自动化测试流程

```bash
# 1. 启动并导航
stagehand open https://example.com --wait load

# 2. 获取初始快照
stagehand snapshot --compact > initial-state.txt

# 3. 执行交互
stagehand fill "#search" "test query"
stagehand press Enter

# 4. 等待结果加载
stagehand wait selector ".results" --timeout 10000

# 5. 截图保存
stagehand screenshot ./search-results.png

# 6. 验证结果
stagehand is visible ".result-item"
```

### 数据采集流程

```bash
# 1. 导航到目标页面
stagehand open https://news.example.com

# 2. 截图存档
stagehand screenshot ./news-$(date +%Y%m%d).png --full-page

# 3. 获取内容
stagehand get markdown "article"

# 4. 关闭浏览器
stagehand stop
```

## 故障排除

| 问题 | 解决方案 |
|------|----------|
| 连接被拒绝 | 运行 `stagehand start` 启动守护进程 |
| 浏览器未响应 | 使用 `stagehand stop --force` 强制停止 |
| 超时错误 | 增加 `--timeout` 参数值 |
| CDP 连接失败 | 检查 Chrome 是否以 `--remote-debugging-port` 启动 |

### 查看详细日志

```bash
# 启用详细输出
stagehand --verbose open https://example.com

---

<a id='architecture-overview'></a>

## 系统架构总览

### Related Pages

Related topics: [Stagehand 简介](#introduction), [Handler 处理系统](#handler-system)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
- [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)
- [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)
</details>

# 系统架构总览

## 1. 项目概述

Stagehand 是一个基于 Chrome DevTools Protocol (CDP) 的浏览器自动化 CLI 工具和 SDK，提供命令行界面和编程 API 两种交互方式。该项目采用 monorepo 结构，使用 pnpm workspace 管理多个包。

核心能力包括：

- 浏览器页面导航与交互
- 元素定位与操作
- 截图与 DOM 快照
- 网络请求捕获
- 本地浏览器发现与连接
- Daemon 进程管理

Sources: [packages/cli/src/index.ts:1-50]()

## 2. 整体架构

Stagehand 采用客户端-服务器架构，核心组件包括：

```mermaid
graph TD
    subgraph CLI层
        A[CLI Commands] --> B[runCommand]
        B --> C[runDaemon]
    end
    
    subgraph 通信层
        D[Unix Socket] <--> E[WebSocket Bridge]
        F[Lock File] 
    end
    
    subgraph Daemon层
        G[Browser Daemon] --> H[Playwright Page]
        H --> I[Accessibility Snapshot]
    end
    
    subgraph 本地发现
        J[CDP Discovery] --> K[DevTools Active Port]
        K --> L[WebSocket Target]
    end
    
    A --> D
    C --> D
    G --> J
```

Sources: [packages/cli/src/index.ts:200-300]()

## 3. CLI 命令体系

CLI 使用 commander.js 框架实现，所有命令都通过 `runCommand` 函数统一路由到 Daemon 进程执行。

### 3.1 命令分类表

| 类别 | 命令 | 功能描述 |
|------|------|----------|
| 导航 | `open`, `goto` | 页面导航 |
| 元素 | `click`, `dblclick`, `hover` | 元素交互 |
| 输入 | `fill`, `select`, `type`, `press` | 文本与选择操作 |
| 查询 | `get`, `is`, `snapshot` | 页面信息获取 |
| 截图 | `screenshot` | 页面截图 |
| 坐标 | `scroll`, `drag` | 视口操作 |
| 网络 | `network` | 网络请求捕获 |
| 多页 | `pages`, `newpage` | 多标签页管理 |
| 守护 | `start`, `stop`, `status` | Daemon 控制 |

Sources: [packages/cli/src/index.ts:50-200]()

### 3.2 命令执行流程

```mermaid
sequenceDiagram
    participant CLI as CLI Client
    participant Socket as Unix Socket
    participant Daemon as Browser Daemon
    participant Browser as Playwright Browser
    
    CLI->>Socket: sendCommand(command, args)
    Socket->>Daemon: 转发请求
    Daemon->>Browser: 执行操作
    Browser-->>Daemon: 返回结果
    Daemon-->>Socket: 序列化响应
    Socket-->>CLI: 返回结果
    CLI->>CLI: output(result, json)
```

Sources: [packages/cli/src/index.ts:300-400]()

## 4. Daemon 基础设施

Daemon 是长期运行的浏览器进程管理服务，通过 Unix Socket 与 CLI 通信。

### 4.1 Socket 通信机制

```typescript
// Socket 路径: /tmp/browse-{session}.sock
function getSocketPath(session: string): string {
  return path.join(os.tmpdir(), `browse-${session}.sock`);
}
```

Sources: [packages/cli/src/index.ts:350-360]()

### 4.2 文件锁机制

系统使用 O_EXCL 模式的原子文件创建实现互斥锁，防止多进程竞争：

```typescript
async function acquireLock(
  session: string,
  timeoutMs: number = 10000
): Promise<boolean> {
  const lockPath = getLockPath(session);
  // O_EXCL 确保原子创建
  const handle = await fs.open(lockPath, "wx");
  await handle.write(String(process.pid));
}
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| session | string | "default" | 会话标识符 |
| timeoutMs | number | 10000 | 锁等待超时 |

Sources: [packages/cli/src/index.ts:380-420]()

### 4.3 连接重试策略

当连接失败时，系统自动执行三级重试：

| 重试次数 | 策略 | 动作 |
|----------|------|------|
| 0 | 短暂等待 | 等待 200ms 后重试 |
| 1 | 重启 Daemon | 不清理状态重启 |
| 2 | 完全清理 | 杀死进程、清理文件、重启 |

Sources: [packages/cli/src/index.ts:450-500]()

## 5. 本地模式策略系统

本地模式支持三种策略：`auto`、`isolated` 和 `cdp`。

### 5.1 策略决策流程

```mermaid
graph TD
    A[resolveLocalStrategy] --> B{strategy === isolated?}
    B -->|是| C[使用 headless + viewport]
    B -->|否| D{strategy === cdp?}
    D -->|是| E[解析 cdpTarget]
    D -->|否| F[discoverLocalCdp]
    F --> G{发现浏览器?}
    G -->|是| H[连接现有浏览器]
    G -->|否| I[isolated-fallback]
```

Sources: [packages/cli/src/local-strategy.ts:30-70]()

### 5.2 策略类型对比

| 策略 | 说明 | 使用场景 |
|------|------|----------|
| `auto` | 自动发现或创建 | 默认模式，智能选择 |
| `isolated` | 启动独立浏览器实例 | 完全隔离的环境 |
| `cdp` | 连接到指定 CDP 端点 | 复用现有浏览器会话 |

Sources: [packages/cli/src/local-strategy.ts:10-50]()

### 5.3 本地信息源

| 来源类型 | 说明 | 提示信息 |
|----------|------|----------|
| `attached-existing` | 连接已存在的调试浏览器 | 提示使用 `--auto-connect` |
| `attached-explicit` | 显式指定 CDP 目标 | - |
| `isolated` | 独立启动的浏览器 | 提示切换到 attached 模式 |
| `isolated-fallback` | 无法发现时的回退 | - |

Sources: [packages/cli/src/local-strategy.ts:50-80]()

## 6. CDP 发现机制

CDP (Chrome DevTools Protocol) 发现用于自动找到本地运行的 Chrome 浏览器实例。

### 6.1 发现流程

```mermaid
graph LR
    A[读取 DevToolsActivePort] --> B{端口可达?}
    B -->|否| C[cleanup 过期文件]
    B -->|是| D[构建 WebSocket URL]
    E[探测 JSON Version] --> F{成功?}
    F -->|是| D
    F -->|否| G[探测 WebSocket]
```

Sources: [packages/cli/src/local-cdp-discovery.ts:100-150]()

### 6.2 WebSocket 探测

系统通过低层 TCP 握手检测 WebSocket 支持：

```typescript
async function probeWebSocket(port: number): Promise<boolean> {
  // 发送 HTTP Upgrade 请求
  const response = await performWebSocketHandshake(port, wsKey);
  // 检查 101 Switching Protocols 响应
  return /^HTTP\/1\.[01] 101(?:\s|$)/.test(response);
}
```

Sources: [packages/cli/src/local-cdp-discovery.ts:50-80]()

## 7. 全局配置选项

CLI 全局选项通过 `GlobalOpts` 接口定义：

| 选项 | 类型 | 说明 |
|------|------|------|
| `--session` | string | 会话标识 |
| `--headless` | boolean | 无头模式 |
| `--headed` | boolean | 窗口模式 |
| `--json` | boolean | JSON 输出 |
| `--ws` | string | WebSocket 地址 |
| `--connect` | string | 远程连接地址 |
| `--proxies` | boolean | 启用代理 (远程) |
| `--region` | string | 区域设置 (远程) |
| `--block-ads` | boolean | 广告拦截 (远程) |

Sources: [packages/cli/src/index.ts:500-550]()

## 8. 网络捕获系统

系统提供完整的网络请求/响应捕获能力。

### 8.1 捕获数据结构

```typescript
interface PendingRequest {
  id: string;
  timestamp: string;
  method: string;
  url: string;
  headers: Record<string, string>;
  body: string | null;
  resourceType: string;
}
```

### 8.2 文件存储结构

每个请求保存到独立目录：

```
{networkDir}/
  └── {counter:3d}-{method}-{domain}-{pathSlug}/
      ├── request.json   # 请求元数据
      └── response.json  # 响应元数据
```

Sources: [packages/cli/src/index.ts:100-180]()

## 9. 页面信息获取

`snapshot` 命令提供可访问性树快照功能：

```typescript
case "snapshot": {
  const snapshot = await page!.snapshot();
  return {
    tree: snapshot.formattedTree,
    xpathMap: snapshot.xpathMap,
    urlMap: snapshot.urlMap,
  };
}
```

| 输出字段 | 类型 | 说明 |
|----------|------|------|
| `tree` | string | 格式化的可访问性树 |
| `xpathMap` | Record | 选择器到 XPath 的映射 |
| `urlMap` | Record | 元素到 URL 的映射 |

Sources: [packages/cli/src/index.ts:250-280]()

## 10. 关键技术栈

| 组件 | 技术选型 |
|------|----------|
| CLI 框架 | commander.js |
| 浏览器自动化 | Playwright |
| 通信协议 | Unix Socket + WebSocket |
| 包管理 | pnpm workspace |

Sources: [pnpm-workspace.yaml](https://github.com/browserbase/stagehand/blob/main/pnpm-workspace.yaml)()

---

<a id='act-api'></a>

## act() 操作执行

### Related Pages

Related topics: [observe() 页面观察](#observe-api), [extract() 数据提取](#extract-api), [Handler 处理系统](#handler-system)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/core/lib/v3/handlers/actHandler.ts](https://github.com/browserbase/stagehand/blob/main/packages/core/lib/v3/handlers/actHandler.ts)
- [packages/core/lib/v3/agent/tools/act.ts](https://github.com/browserbase/stagehand/blob/main/packages/core/lib/v3/agent/tools/act.ts)
- [packages/core/lib/v3/agent/tools/click.ts](https://github.com/browserbase/stagehand/blob/main/packages/core/lib/v3/agent/tools/click.ts)
- [packages/core/lib/v3/agent/tools/type.ts](https://github.com/browserbase/stagehand/blob/main/packages/core/lib/v3/agent/tools/type.ts)
- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
</details>

# act() 操作执行

## 概述

`act()` 是 Stagehand 框架中的核心操作执行机制，负责将高级自然语言指令转换为具体的浏览器自动化操作。该系统通过 Handler-工具（Tool）架构模式，实现了操作意图识别、目标元素定位、操作执行和结果验证的完整流程。

在 Stagehand 的 CLI 工具 `packages/cli/src/index.ts` 中，操作执行通过 `runCommand` 函数与浏览器守护进程通信，守护进程接收指令后调用相应的 Handler 处理逻辑。Sources: [packages/cli/src/index.ts:1-100]()

## 架构设计

### 核心组件关系

```mermaid
graph TD
    A[Agent / LLM] --> B[actHandler]
    B --> C[工具选择]
    C --> D[click.ts]
    C --> E[type.ts]
    C --> F[其他工具]
    D --> G[ElementHandler]
    E --> G
    F --> G
    G --> H[Playwright Page API]
    H --> I[浏览器执行]
    I --> J[结果验证]
    J --> K[状态反馈]
```

### 执行流程

| 阶段 | 组件 | 职责 |
|------|------|------|
| 意图解析 | actHandler.ts | 解析 LLM 生成的指令，提取操作类型和参数 |
| 工具路由 | act.ts | 根据操作类型选择对应的工具模块 |
| 元素定位 | 各工具模块 | 使用 XPath/CSS 选择器定位目标元素 |
| 操作执行 | ElementHandler | 调用 Playwright API 执行具体操作 |
| 结果验证 | Handler 返回值 | 返回执行结果和状态信息 |

Sources: [packages/core/lib/v3/handlers/actHandler.ts:1-50]()
Sources: [packages/core/lib/v3/agent/tools/act.ts:1-50]()

## 操作类型

### 元素交互操作

#### click 点击操作

`click` 操作用于模拟鼠标点击事件，支持多种变体：

| 命令 | 描述 | 参数 |
|------|------|------|
| `click` | 点击元素 | selector, button, count, force |
| `click_xy` | 坐标点击 | x, y, button, count |
| `dblclick` | 双击 | selector |
| `rightclick` | 右键菜单 | selector |

CLI 实现示例：

```typescript
program
  .command("click <selector>")
  .description("Click element")
  .option("-b, --button <btn>", "Mouse button", "left")
  .option("-c, --count <n>", "Click count", "1")
  .option("--force", "Force click")
  .option("--xpath", "Return XPath of clicked element")
  .action(async (selector: string, cmdOpts) => {
    const opts = program.opts<GlobalOpts>();
    const result = await runCommand("click", [
      selector,
      {
        button: cmdOpts.button,
        clickCount: parseInt(cmdOpts.count),
        force: cmdOpts.force,
      },
    ]);
    output(result, opts.json ?? false);
  });
```

Sources: [packages/core/lib/v3/agent/tools/click.ts:1-80]()
Sources: [packages/cli/src/index.ts:200-250]()

#### type 输入操作

`type` 操作用于模拟键盘输入，支持人类化输入模式：

| 选项 | 类型 | 描述 |
|------|------|------|
| `text` | string | 要输入的文本内容 |
| `delay` | number | 击键间隔（毫秒） |
| `mistakes` | boolean | 启用类人错误模拟 |

```typescript
program
  .command("type <text>")
  .description("Type text")
  .option("-d, --delay <ms>", "Delay between keystrokes")
  .option("--mistakes", "Enable human-like typing with mistakes")
  .action(async (text: string, cmdOpts) => {
    const result = await runCommand("type", [
      text,
      {
        delay: cmdOpts.delay ? parseInt(cmdOpts.delay) : undefined,
        mistakes: cmdOpts.mistakes,
      },
    ]);
  });
```

Sources: [packages/core/lib/v3/agent/tools/type.ts:1-60]()
Sources: [packages/cli/src/index.ts:350-400]()

#### fill 填充操作

`fill` 专门用于填充表单输入框，默认在填充完成后按 Enter 键：

| 参数 | 类型 | 描述 |
|------|------|------|
| `selector` | string | 输入框选择器 |
| `value` | string | 填充值 |
| `pressEnter` | boolean | 是否按 Enter 确认 |

Sources: [packages/cli/src/index.ts:280-330]()

#### select 下拉选择

`select` 用于选择下拉菜单选项：

```typescript
program
  .command("select <selector> <values...>")
  .description("Select option(s)")
  .action(async (selector: string, values: string[]) => {
    const result = await runCommand("select", [selector, values]);
  });
```

### 坐标操作

#### hover 悬停

悬停到指定坐标位置：

```typescript
program
  .command("hover <x> <y>")
  .description("Hover at coordinates")
  .option("--xpath", "Return XPath of hovered element")
  .action(async (x: string, y: string, cmdOpts) => {
    const result = await runCommand("hover", [
      parseFloat(x),
      parseFloat(y),
      { returnXPath: cmdOpts.xpath },
    ]);
  });
```

#### scroll 滚动

在指定位置执行滚动操作：

```typescript
program
  .command("scroll <x> <y> <deltaX> <deltaY>")
  .description("Scroll at coordinates")
  .option("--xpath", "Return XPath of scrolled element")
  .action(async (x: string, y: string, dx: string, dy: string, cmdOpts) => {
    const result = await runCommand("scroll", [
      parseFloat(x),
      parseFloat(y),
      parseFloat(dx),
      parseFloat(dy),
      { returnXPath: cmdOpts.xpath },
    ]);
  });
```

Sources: [packages/cli/src/index.ts:420-470]()

### 键盘操作

#### press 按键

模拟按下指定键盘按键：

| 参数 | 示例值 |
|------|--------|
| 修饰键 | Enter, Tab, Escape |
| 组合键 | Cmd+A, Ctrl+C, Shift+Tab |
| 功能键 | F1-F12 |

```typescript
program
  .command("press <key>")
  .alias("key")
  .description("Press key (e.g., Enter, Tab, Escape, Cmd+A)")
  .action(async (key: string) => {
    const result = await runCommand("press", [key]);
  });
```

Sources: [packages/cli/src/index.ts:380-410]()

### 状态检查操作

#### is 检查元素状态

验证元素的可见性或选中状态：

```typescript
program
  .command("is <check> <selector>")
  .description("Check element state: visible, checked")
  .action(async (check: string, selector: string) => {
    const result = await runCommand("is", [check, selector]);
  });
```

| 检查类型 | 描述 |
|----------|------|
| `visible` | 元素是否可见 |
| `checked` | 复选框/单选框是否选中 |

#### get 获取页面信息

获取页面或元素的各类信息：

```typescript
program
  .command("get <what> [selector]")
  .description(
    "Get page info: url, title, text, html, markdown, value, box, visible, checked",
  )
  .action(async (what: string, selector?: string) => {
    const result = await runCommand("get", [what, selector]);
  });
```

Sources: [packages/cli/src/index.ts:490-520]()

### 导航操作

#### open 页面导航

```typescript
program
  .command("open <url>")
  .alias("goto")
  .description("Navigate to URL")
  .option("--wait <state>", "Wait state: load, domcontentloaded, networkidle")
  .option("-t, --timeout <ms>", "Navigation timeout", "30000")
  .action(async (url: string, cmdOpts) => {
    // 支持等待状态配置和超时控制
  });
```

Sources: [packages/cli/src/index.ts:560-620]()

### 特殊操作

#### wait 等待操作

等待特定条件满足：

```typescript
program
  .command("wait <type> [arg]")
  .description("Wait for: load, selector, timeout")
  .option("-t, --timeout <ms>", "Timeout", "30000")
  .option("-s, --state <state>", "Element state: visible, hidden, attached, detached")
  .action(async (type: string, arg: string | undefined, cmdOpts) => {
    const result = await runCommand("wait", [
      type,
      arg,
      { timeout: parseInt(cmdOpts.timeout), state: cmdOpts.state },
    ]);
  });
```

| 等待类型 | 参数 | 描述 |
|----------|------|------|
| `load` | - | 等待页面加载 |
| `selector` | 选择器 | 等待元素出现 |
| `timeout` | 毫秒 | 等待指定时间 |

#### eval JavaScript 执行

在页面上下文中执行任意 JavaScript：

```typescript
program
  .command("eval <expression>")
  .description("Evaluate JavaScript in page")
  .action(async (expr: string) => {
    const result = await runCommand("eval", [expr]);
  });
```

Sources: [packages/cli/src/index.ts:540-560]()

## 执行上下文管理

### Session 隔离机制

Stagehand 使用 Session 来隔离不同的浏览器上下文：

```typescript
interface GlobalOpts {
  ws?: string;
  headless?: boolean;
  headed?: boolean;
  json?: boolean;
  session?: string;
  connect?: string;
  proxies?: boolean;
  advancedStealth?: boolean;
  solveCaptchas?: boolean;
  region?: string;
  keepAlive?: boolean;
  sessionTimeout?: number;
  blockAds?: boolean;
}

function getSession(opts: GlobalOpts): string {
  return opts.session ?? process.env.BROWSE_SESSION ?? "default";
}
```

Sources: [packages/cli/src/index.ts:700-750]()

### 守护进程架构

CLI 与浏览器守护进程之间通过 Unix Socket 进行通信：

```mermaid
graph LR
    A[CLI Client] -->|runCommand| B[Unix Socket]
    B --> C[Daemon Process]
    C --> D[Chrome DevTools Protocol]
    D --> E[Browser Instance]
```

守护进程管理包括：

| 功能 | 描述 |
|------|------|
| `start` | 启动浏览器守护进程 |
| `stop` | 停止守护进程 |
| `status` | 检查守护进程状态 |
| `daemon` | 以守护进程模式运行 |

```typescript
program
  .command("start")
  .description("Start browser daemon")
  .action(async () => {
    const session = getSession(opts);
    if (await isDaemonRunning(session)) {
      console.log(JSON.stringify({ status: "already running", session }));
      return;
    }
    await ensureDaemon(session, isHeadless(opts));
  });
```

Sources: [packages/cli/src/index.ts:620-680]()

## 操作执行重试机制

当命令执行失败时，系统会自动进行重试：

```typescript
async function sendCommand(
  session: string,
  command: string,
  args: unknown[],
  headless: boolean,
  retries: number = 3,
): Promise<unknown> {
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      return await sendCommandOnce(session, command, args);
    } catch (err) {
      if (attempt === retries || command === "stop") {
        throw err;
      }

      const errMsg = err instanceof Error ? err.message : String(err);
      const isConnectionError =
        errMsg.includes("ENOENT") ||
        errMsg.includes("ECONNREFUSED") ||
        errMsg.includes("Connection failed");

      if (!isConnectionError) {
        throw err;
      }

      // 重试策略
      if (attempt === 0) {
        await new Promise((r) => setTimeout(r, 200));
        continue;
      }
      if (attempt === 1) {
        await ensureDaemon(session, headless);
        continue;
      }

      await killChromeProcesses(session);
      await cleanupStaleFiles(session);
      await ensureDaemon(session, headless);
    }
  }
}
```

| 重试次数 | 策略 | 原因 |
|----------|------|------|
| 0 | 短暂等待后重试 | Socket 可能暂时不可用 |
| 1 | 重启守护进程 | 守护进程可能无响应 |
| 2 | 清理并完全重启 | 清理残留状态 |

Sources: [packages/cli/src/index.ts:800-870]()

## 输出格式

操作执行结果支持两种输出格式：

| 模式 | 触发方式 | 输出内容 |
|------|----------|----------|
| 标准输出 | 默认 | 格式化的人类可读输出 |
| JSON 模式 | `--json` 选项 | 结构化 JSON 数据 |

```typescript
function output(result: unknown, asJson: boolean): void {
  if (asJson) {
    console.log(JSON.stringify(result, null, 2));
  } else {
    // 格式化输出
    console.log(result);
  }
}
```

## 总结

`act()` 操作执行系统是 Stagehand 自动化能力的核心，它通过以下设计实现：

1. **分层架构**：Handler 层负责指令解析，工具层负责具体操作
2. **灵活的命令路由**：CLI 通过统一的 `runCommand` 接口支持多种操作类型
3. **健壮的错误处理**：自动重试机制和详细的错误信息
4. **会话隔离**：通过 Session 实现多任务并行执行
5. **丰富的操作类型**：覆盖点击、输入、导航、状态检查等常见自动化场景

---

<a id='extract-api'></a>

## extract() 数据提取

### Related Pages

Related topics: [act() 操作执行](#act-api), [observe() 页面观察](#observe-api), [Handler 处理系统](#handler-system)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
- [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)
- [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)
- [packages/core/lib/v3/handlers/extractHandler.ts](https://github.com/browserbase/stagehand/blob/main/packages/core/lib/v3/handlers/extractHandler.ts)
- [packages/core/lib/v3/agent/tools/extract.ts](https://github.com/browserbase/stagehand/blob/main/packages/core/lib/v3/agent/tools/extract.ts)
- [packages/core/lib/zodCompat.ts](https://github.com/browserbase/stagehand/blob/main/packages/core/lib/zodCompat.ts)
</details>

# extract() 数据提取

## 概述

`extract()` 是 Stagehand 框架中的核心数据提取方法，允许开发者从网页内容中提取结构化数据。该功能通过 Zod schema 定义期望的数据结构，由 AI 模型智能解析页面内容并返回类型安全的提取结果。

## 核心功能

### 1. Schema 驱动的数据提取

Stagehand 使用 Zod 作为数据验证和类型定义的基础。开发者可以通过 Zod schema 定义期望的输出结构：

```typescript
import { extract } from "@browserbase/stagehand";
import { z } from "zod";

const schema = z.object({
  title: z.string(),
  price: z.number(),
  inStock: z.boolean(),
});

const result = await extract(page, { 
  instruction: "提取产品名称、价格和库存状态",
  schema 
});
```

### 2. 指令引导的提取

`extract()` 方法支持自然语言指令，让 AI 模型理解需要提取哪些信息：

| 参数 | 类型 | 描述 |
|------|------|------|
| `instruction` | `string` | 描述需要提取的数据的自然语言指令 |
| `schema` | `ZodSchema` | 定义提取数据的 Zod schema |
| `maxTokens` | `number` | 最大响应 token 数（可选） |

## 工作流程

```mermaid
graph TD
    A[调用 extract] --> B[解析 Zod Schema]
    B --> C[生成 AI Prompt]
    C --> D[执行 DOM 解析]
    D --> E[提取匹配数据]
    E --> F[Schema 验证]
    F --> G{验证通过?}
    G -->|是| H[返回结构化数据]
    G -->|否| I[抛出验证错误]
```

## 与 Zod 的集成

Stagehand 通过 `zodCompat.ts` 实现与 Zod 的深度集成：

```typescript
// packages/core/lib/zodCompat.ts
import { z } from "zod";

// 支持的 Zod 类型映射
const typeMap = {
  string: "text",
  number: "number", 
  boolean: "boolean",
  array: "array",
  object: "object",
};
```

### 支持的 Zod 类型

| Zod 类型 | 提取行为 | 说明 |
|----------|----------|------|
| `z.string()` | 文本提取 | 返回 DOM 元素的文本内容 |
| `z.number()` | 数值提取 | 解析文本中的数字 |
| `z.boolean()` | 布尔提取 | 识别 yes/no、true/false 等 |
| `z.array(z.string())` | 列表提取 | 返回多个匹配元素 |
| `z.object({...})` | 嵌套对象 | 递归提取复杂结构 |

## 错误处理

```mermaid
graph LR
    A[提取操作] --> B{执行结果}
    B -->|成功| C[返回数据]
    B -->|验证失败| D[ZodError]
    B -->|超时| E[TimeoutError]
    B -->|无匹配| F[NoMatchError]
```

### 常见错误类型

| 错误类型 | 描述 | 处理方式 |
|----------|------|----------|
| `ValidationError` | Schema 验证失败 | 检查 schema 定义 |
| `TimeoutError` | 操作超时 | 增加 timeout 参数 |
| `NoMatchError` | 未找到匹配元素 | 调整选择器或指令 |

## 使用示例

### 基本用法

```typescript
import { stagehand } from "@browserbase/stagehand";
import { z } from "zod";

const page = await stagehand.init();

const product = await page.extract({
  instruction: "提取产品标题和价格",
  schema: z.object({
    title: z.string(),
    price: z.number(),
  }),
});

console.log(product);
// { title: "iPhone 15 Pro", price: 999 }
```

### 复杂嵌套结构

```typescript
const schema = z.object({
  products: z.array(z.object({
    name: z.string(),
    price: z.number(),
    variants: z.array(z.object({
      color: z.string(),
      inStock: z.boolean(),
    })),
  })),
  totalResults: z.number(),
});

const data = await page.extract({
  instruction: "提取所有产品及其变体信息",
  schema,
});
```

## 与其他模块的协同

```mermaid
graph TD
    subgraph 核心模块
        A[extractHandler.ts]
        B[extract.ts]
        C[zodCompat.ts]
    end
    
    subgraph 依赖关系
        D[snapshot 获取 DOM]
        E[AI 模型解析]
        F[Zod 验证]
    end
    
    A --> B
    B --> C
    A --> D
    A --> E
    A --> F
    
    style A fill:#e1f5fe
    style B fill:#fff3e0
    style C fill:#e8f5e9
```

## 配置选项

| 选项 | 默认值 | 描述 |
|------|--------|------|
| `timeout` | `30000` | 操作超时时间（毫秒） |
| `retries` | `3` | 失败重试次数 |
| `model` | `gpt-4o` | 使用的 AI 模型 |
| `verbose` | `false` | 启用详细日志 |

## 最佳实践

1. **使用精确的指令**：指令越具体，提取结果越准确
2. **选择合适的 Schema**：避免过于复杂的嵌套结构
3. **处理可选字段**：使用 `z.string().optional()` 处理可能缺失的字段
4. **设置合理的超时**：复杂页面需要更长超时时间
5. **验证返回数据**：即使通过 schema 验证，也建议进行运行时检查

## 相关资源

- [Stagehand 官方文档](https://docs.browserbase.com/stagehand)
- [Zod 官方文档](https://zod.dev)
- [Browserbase 平台](https://browserbase.com)

---

<a id='observe-api'></a>

## observe() 页面观察

### Related Pages

Related topics: [act() 操作执行](#act-api), [extract() 数据提取](#extract-api), [DOM 与无障碍树](#dom-accessibility)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
- [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)
- [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)
</details>

# observe() 页面观察

## 概述

`observe()` 是 stagehand 框架中的核心页面观察功能，用于实时捕获和分析网页的当前状态。该功能通过无障碍树（Accessibility Tree）快照机制，获取页面的 DOM 结构、元素属性、位置信息等关键数据，为 AI 代理提供理解和操作网页的能力。

页面观察功能在架构中扮演着"感知层"的角色，是连接浏览器渲染结果与 AI 决策引擎的关键桥梁。通过标准化的快照格式，系统能够将复杂的 DOM 结构转化为 AI 可理解的语义化表示。

## 核心组件

### Snapshot 快照系统

快照系统负责从浏览器页面提取无障碍信息，生成结构化的页面描述。

| 组件 | 职责 | 输出格式 |
|------|------|----------|
| `capture.ts` | 底层无障碍数据采集 | 原始 AX 节点树 |
| `index.ts` | 快照格式化与映射构建 | 树形结构 + XPath/URL 映射 |

快照系统的工作流程：

```mermaid
graph TD
    A[浏览器页面] --> B[Playwright snapshot API]
    B --> C[原始 AX 节点]
    C --> D[格式化处理]
    D --> E[formattedTree 树形输出]
    D --> F[xpathMap XPath 映射]
    D --> G[urlMap URL 映射]
```

### Observe Handler 处理层

`observeHandler.ts` 实现了页面观察的核心逻辑，负责协调快照采集、结果处理和错误管理。

处理流程包含以下关键阶段：

1. **初始化阶段** - 验证观察上下文和目标页面
2. **采集阶段** - 调用底层快照 API 获取无障碍树
3. **处理阶段** - 格式化节点数据，构建引用映射
4. **返回阶段** - 输出结构化的观察结果

### CLI 集成接口

在 CLI 工具中，`snapshot` 命令提供了直接调用观察功能的入口：

```typescript
program
  .command("snapshot")
  .description("Get accessibility tree snapshot")
  .option("-c, --compact", "Output tree only (no xpath map)")
```

输出格式示例：

```json
{
  "tree": "页面元素的树形文本表示",
  "xpathMap": {
    "elementRef1": "/html/body/div[1]/button[2]",
    "elementRef2": "/html/body/main/section[1]"
  },
  "urlMap": {
    "linkRef1": "https://example.com/page",
    "linkRef2": "https://api.example.com/data"
  }
}
```

## 快照数据模型

### 节点结构

每个无障碍树节点包含以下核心属性：

| 属性 | 类型 | 描述 |
|------|------|------|
| `role` | string | 元素的 ARIA 角色 |
| `name` | string | 元素的辅助名称 |
| `value` | string | 元素的值属性 |
| `description` | string | 元素的描述信息 |
| `state` | string[] | 元素状态数组 |
| `children` | Node[] | 子节点列表 |

### 引用映射机制

系统维护两套关键映射表：

**XPath 映射** - 将内部引用转换为 XPath 表达式，支持精确定位 DOM 元素
**URL 映射** - 记录页面中的链接和资源 URL，便于后续操作

```mermaid
graph LR
    A[snapshot 结果] --> B[tree 格式化文本]
    A --> C[xpathMap 引用表]
    A --> D[urlMap URL 表]
    C --> E[click 元素定位]
    C --> F[fill 输入定位]
    D --> G[navigate 链接访问]
```

## 配置选项

### 紧凑模式 (Compact Mode)

使用 `--compact` 或 `-c` 选项时，快照输出仅包含树形结构，不包含映射表：

```bash
browse snapshot --compact
```

适用于需要快速查看页面结构的场景，减少输出量。

### 全局输出控制

| 选项 | 说明 | 默认值 |
|------|------|--------|
| `--json` | 输出完整 JSON 格式 | false |
| 紧凑模式 | 仅输出树形文本 | false |

## 与其他模块的协作

### 无障碍树采集 (capture.ts)

底层采集模块通过 Playwright 的 `snapshot()` 方法获取页面的无障碍表示。该模块负责：

- 遍历 DOM 节点构建 AX 树
- 提取元素的语义化信息
- 过滤无关的内部节点

### 本地模式发现 (local-cdp-discovery.ts)

页面观察功能依赖于与浏览器实例的 CDP 连接。CDP 发现机制确保 CLI 能够正确连接到本地或远程浏览器实例：

```mermaid
graph TD
    A[启动浏览器] --> B[CDP 端口检测]
    B --> C{发现可用端口}
    C -->|成功| D[建立 WebSocket 连接]
    C -->|失败| E[使用默认端口]
    D --> F[初始化 snapshot 服务]
```

### 本地策略解析 (local-strategy.ts)

根据配置策略，系统选择合适的浏览器连接方式：

| 策略 | 说明 | 适用场景 |
|------|------|----------|
| `isolated` | 独立 Chromium 实例 | 默认隔离环境 |
| `cdp` | 连接到已有浏览器 | 复用已有会话 |
| `auto` | 自动发现可用浏览器 | 智能选择 |

## 使用场景

### 1. 页面状态分析

在执行自动化操作前，先观察页面结构：

```bash
browse open https://example.com
browse snapshot
```

### 2. 元素定位验证

通过 XPath 映射验证元素选择器的正确性：

```bash
browse snapshot --json
# 检查 xpathMap 中的路径是否与预期匹配
```

### 3. AI 代理感知

为 AI 代理提供页面状态的语义化表示，支持决策制定：

```json
{
  "tree": "form\n  input[name='username']\n  input[name='password']\n  button[type='submit']",
  "xpathMap": {
    "username": "/html/body/form/input[1]",
    "password": "/html/body/form/input[2]",
    "submit": "/html/body/form/button"
  }
}
```

## 技术规格

### 性能特性

| 指标 | 典型值 | 说明 |
|------|--------|------|
| 采集延迟 | < 100ms | 中等复杂度页面 |
| 树深度限制 | 无 | 完整遍历 |
| 输出大小 | 10KB - 500KB | 取决于页面复杂度 |

### 错误处理

观察功能实现了完善的错误处理机制：

- **连接失败** - 自动重试并清理陈旧状态
- **超时处理** - 默认 30 秒超时保护
- **部分失败** - 返回已采集的部分数据

## 总结

`observe()` 页面观察功能是 stagehand 框架的感知核心，通过标准化的无障碍树快照机制，将网页的视觉和语义信息转化为 AI 可理解的结构化数据。该功能与 CLI 工具、CDP 连接层、本地策略模块紧密协作，为浏览器自动化操作提供了稳定、可靠的页面状态感知能力。

---

**Sources:** [packages/cli/src/index.ts:280-320](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts) | [packages/cli/src/local-strategy.ts:1-100](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts) | [packages/cli/src/local-cdp-discovery.ts:1-80](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)

---

<a id='agent-system'></a>

## Agent 代理系统

### Related Pages

Related topics: [Handler 处理系统](#handler-system)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
- [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)
- [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)

> **注意**：用户请求的 Agent 系统核心文件（如 `packages/core/lib/v3/agent/AgentClient.ts`、`AgentProvider.ts` 等）未包含在提供的上下文中。本页面基于 CLI 与 Agent 系统交互的代码进行分析。

</details>

# Agent 代理系统

## 概述

Stagehand 的 Agent 代理系统是浏览器自动化操作的核心引擎，负责管理浏览器会话、执行自动化命令、处理网络请求捕获以及维护浏览器状态。该系统通过 CLI 接口和核心库协同工作，为 AI 代理提供可观测、可控制的浏览器操作能力。

## 系统架构

### 整体架构图

```mermaid
graph TD
    subgraph CLI层 ["CLI 接口层"]
        CLI[packages/cli/src/index.ts]
        Cmds[命令定义]
    end
    
    subgraph Agent核心 ["Agent 核心系统"]
        AC[AgentClient]
        AP[AgentProvider]
        Handler[v3AgentHandler]
        ActionMap[actionMapping]
    end
    
    subgraph Daemon层 ["Daemon 守护进程"]
        Socket[Unix Socket]
        Chrome[Chrome Browser]
        CDP[CDP Protocol]
    end
    
    CLI --> Cmds
    Cmds --> AC
    AC --> AP
    AP --> Handler
    Handler --> ActionMap
    ActionMap --> Socket
    Socket --> Chrome
    Chrome --> CDP
    
    LocalCDP[local-cdp-discovery] --> AP
    LocalStrat[local-strategy.ts] --> AP
```

## 核心组件

### 1. CLI 命令接口层

CLI 层定义了所有与浏览器交互的命令，通过 `runCommand` 函数与 Agent 系统通信。

**主要命令类别**：

| 类别 | 命令 | 功能 |
|------|------|------|
| 导航 | `open`, `goto` | 打开 URL |
| 元素操作 | `click`, `fill`, `select`, `upload` | 操作页面元素 |
| 状态检查 | `is`, `wait`, `get` | 检查元素状态 |
| 键盘鼠标 | `type`, `press`, `hover`, `scroll`, `drag` | 模拟输入 |
| 网络 | `network on/off`, `network path` | 网络请求捕获 |
| 截图 | `screenshot` | 页面截图 |
| 快照 | `snapshot` | 辅助功能树快照 |
| 标签页 | `pages`, `newpage`, `closepage` | 多标签管理 |

### 2. Daemon 守护进程管理

Daemon 系统负责管理浏览器实例的生命周期。

```typescript
// Socket 路径配置
const SOCKET_DIR = os.tmpdir();

function getSocketPath(session: string): string {
  return path.join(SOCKET_DIR, `browse-${session}.sock`);
}

function getLockPath(session: string): string {
  return path.join(SOCKET_DIR, `browse-${session}.lock`);
}
```

**Daemon 启动流程**：

```mermaid
sequenceDiagram
    participant CLI
    participant Lock
    participant Daemon
    participant Chrome
    
    CLI->>Lock: acquireLock(session)
    Lock-->>CLI: 锁定成功
    CLI->>Daemon: ensureDaemon(session, headless)
    Daemon->>Chrome: 启动/连接 Chrome
    Chrome-->>Daemon: WebSocket Ready
    Daemon->>Lock: releaseLock(session)
```

**关键特性**：
- 基于 `O_EXCL` 的原子文件锁机制防止竞态条件
- 自动检测并清理陈旧的锁文件
- 支持会话超时自动清理

### 3. 本地模式策略

Agent 支持多种本地浏览器连接策略，由 `local-strategy.ts` 定义。

| 策略 | 说明 | 用途 |
|------|------|------|
| `isolated` | 启动独立 Chromium 实例 | 完全隔离的浏览器环境 |
| `cdp` | 连接到指定 CDP 目标 | 复用已有浏览器会话 |
| `auto` | 自动检测可用浏览器 | 优先复用，无则创建新实例 |

```typescript
// Sources: packages/cli/src/local-strategy.ts:18-37
export async function resolveLocalStrategy({
  localConfig,
  headless,
  defaultViewport,
  discoverLocalCdp,
  resolveWsTarget,
}: ResolveLocalStrategyOptions): Promise<ResolvedLocalStrategy>
```

### 4. CDP 发现机制

通过 `local-cdp-discovery.ts` 实现 Chrome DevTools Protocol 端点的自动发现。

```mermaid
graph LR
    A[读取 DevToolsActivePort] --> B{端口可达性检查}
    B -->|可达| C[构建 WebSocket URL]
    B -->|不可达| D[清理陈旧文件]
    C --> E[返回 CDP URL]
    D --> E
```

**发现流程**：
1. 扫描用户数据目录（`userDataDirs`）
2. 读取 `DevToolsActivePort` 文件获取端口信息
3. 验证端口可达性
4. 构建 WebSocket 连接 URL

## 网络捕获系统

### 网络请求监控

Agent 系统提供完整的网络请求捕获能力，捕获结果写入文件系统供 Agent 检查。

```typescript
// Sources: packages/cli/src/index.ts:88-103
interface PendingRequest {
  id: string;
  timestamp: string;
  method: string;
  url: string;
  headers: Record<string, string>;
  body: string | null;
  resourceType: string;
}
```

### 目录结构

```
{networkDir}/
├── {counter}-{method}-{domain}-{pathSlug}/
│   ├── request.json    # 请求详情
│   └── response.json   # 响应详情
```

### 文件名生成规则

```typescript
// Sources: packages/cli/src/index.ts:95-120
function getRequestDirName(
  counter: number,
  method: string,
  url: string,
): string {
  const parsed = new URL(url);
  const domain = sanitizeForFilename(parsed.hostname, 30);
  const pathPart = parsed.pathname.split("/").filter(Boolean)[0] || "root";
  const pathSlug = sanitizeForFilename(pathPart, 20);
  return `${String(counter).padStart(3, "0")}-${method}-${domain}-${pathSlug}`;
}
```

## 命令执行流程

### runCommand 执行机制

```mermaid
graph TD
    Start[CLI Command] --> Check{连接状态检查}
    Check -->|正常| Execute[发送命令]
    Check -->|连接错误| Retry{重试策略}
    
    Retry -->|Attempt 0| Wait[等待 200ms]
    Wait --> Execute
    
    Retry -->|Attempt 1| Restart[重启 Daemon]
    Restart --> Execute
    
    Retry -->|Attempt 2| Cleanup[清理并重启]
    Cleanup --> Execute
    
    Execute --> Success[返回结果]
    Execute --> Error[抛出错误]
```

**错误重试策略**：

| 重试次数 | 策略 | 条件 |
|----------|------|------|
| 0 | 短暂等待 | `ENOENT`, `ECONNREFUSED`, `Connection failed` |
| 1 | 重启 Daemon | 同上 |
| 2 | 完整清理 | 杀死 Chrome 进程 + 清理文件 + 重启 |

## 会话管理

### GlobalOpts 配置选项

| 选项 | 类型 | 说明 |
|------|------|------|
| `ws` | `string` | WebSocket 端点 |
| `headless` | `boolean` | 无头模式 |
| `headed` | `boolean` | 显示浏览器窗口 |
| `json` | `boolean` | JSON 格式输出 |
| `session` | `string` | 会话标识符 |
| `connect` | `string` | 连接模式 |
| `proxies` | `boolean` | 启用代理 (远程) |
| `advancedStealth` | `boolean` | 高级隐身模式 |
| `solveCaptchas` | `boolean` | 自动解验证码 |
| `region` | `string` | 区域设置 (远程) |
| `keepAlive` | `boolean` | 保持连接活跃 |
| `sessionTimeout` | `number` | 会话超时秒数 |
| `blockAds` | `boolean` | 广告拦截 |

### 会话参数构建

```typescript
// Sources: packages/cli/src/index.ts:520-545
function buildSessionParamsFromOpts(
  opts: GlobalOpts,
): Record<string, unknown> | null {
  const params: Record<string, unknown> = {};
  const browserSettings: Record<string, unknown> = {};

  if (opts.proxies) params.proxies = true;
  if (opts.region) params.region = opts.region;
  if (opts.keepAlive) params.keepAlive = true;
  if (opts.sessionTimeout !== undefined) params.timeout = opts.sessionTimeout;

  if (opts.advancedStealth) browserSettings.advancedStealth = true;
  if (opts.blockAds) browserSettings.blockAds = true;
  // ...
}
```

## 命令实现示例

### 元素操作命令

```typescript
// Sources: packages/cli/src/index.ts:185-200
program
  .command("fill <selector> <value>")
  .description("Fill input element (presses Enter by default)")
  .option("--no-press-enter", "Don't press Enter after filling")
  .action(async (selector: string, value: string, cmdOpts) => {
    const pressEnter = cmdOpts.pressEnter !== false;
    const result = await runCommand("fill", [
      selector,
      value,
      { pressEnter },
    ]);
    output(result, opts.json ?? false);
  });
```

### 截图命令

```typescript
// Sources: packages/cli/src/index.ts:320-345
program
  .command("screenshot [path]")
  .description("Take screenshot")
  .option("-f, --full-page", "Full page screenshot")
  .option("-t, --type <type>", "Image type: png, jpeg", "png")
  .option("-q, --quality <n>", "JPEG quality (0-100)")
  .option("--clip <json>", "Clip region as JSON")
  .option("--no-animations", "Disable animations")
  .option("--hide-caret", "Hide text caret");
```

### 辅助功能快照

```typescript
// Sources: packages/cli/src/index.ts:360-380
program
  .command("snapshot")
  .description("Get accessibility tree snapshot")
  .option("-c, --compact", "Output tree only (no xpath map)")
  .action(async (cmdOpts) => {
    const result = (await runCommand("snapshot", [cmdOpts.compact])) as {
      tree: string;
      xpathMap?: Record<string, string>;
      urlMap?: Record<string, string>;
    };
    // ...
  });
```

## 错误处理机制

### Daemon 状态管理

```mermaid
stateDiagram-v2
    [*] --> Stopped
    Stopped --> Starting: start 命令
    Starting --> Running: 启动成功
    Starting --> Failed: 启动失败
    Running --> Stopping: stop 命令
    Running --> Failed: 连接断开
    Stopping --> Stopped: 清理完成
    Failed --> Starting: 重试
    Stopped --> [*]
```

### 锁机制实现

```typescript
// Sources: packages/cli/src/index.ts:490-520
async function acquireLock(
  session: string,
  timeoutMs: number = 10000,
): Promise<boolean> {
  const lockPath = getLockPath(session);
  
  while (Date.now() - startTime < timeoutMs) {
    try {
      // O_EXCL 确保原子性创建
      const handle = await fs.open(lockPath, "wx");
      await handle.write(String(process.pid));
      await handle.close();
      return true;
    } catch (err: unknown) {
      if ((err as NodeJS.ErrnoException).code === "EEXIST") {
        // 检查持有者是否存活
        try {
          const holderPid = parseInt(await fs.readFile(lockPath, "utf-8"));
          process.kill(holderPid, 0);
          await new Promise((r) => setTimeout(r, 100));
        } catch {
          // 清理陈旧锁
          await fs.unlink(lockPath);
        }
      }
    }
  }
  return false;
}
```

## 扩展命令系统

Agent 系统支持通过命令模式（Command Pattern）轻松扩展新功能：

```typescript
program
  .command("<command> <args...>")
  .description("命令描述")
  .option("-x, --option <value>", "选项说明")
  .action(async (args, cmdOpts) => {
    const result = await runCommand("command_name", [
      args,
      { /* options */ }
    ]);
    output(result, opts.json ?? false);
  });
```

## 总结

Stagehand 的 Agent 代理系统提供了完整的浏览器自动化能力：

1. **Daemon 管理**：基于 Unix Socket 的进程间通信，支持多会话隔离
2. **命令系统**：统一的命令接口，覆盖所有浏览器操作
3. **网络监控**：完整的请求/响应捕获机制
4. **本地策略**：灵活的浏览器连接策略（隔离/CDP/自动）
5. **错误恢复**：多级重试和自动清理机制
6. **会话管理**：完善的会话状态和配置管理

---

<a id='handler-system'></a>

## Handler 处理系统

### Related Pages

Related topics: [act() 操作执行](#act-api), [extract() 数据提取](#extract-api), [observe() 页面观察](#observe-api)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
- [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)
- [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)
</details>

# Handler 处理系统

## 概述

Handler 处理系统是 Stagehand 框架的核心组件，负责在浏览器环境中执行自动化操作。该系统通过统一的命令调度机制，将高层操作指令（如 `click`、`type`、`hover` 等）转换为底层的浏览器 CDP (Chrome DevTools Protocol) 调用。Sources: [packages/cli/src/index.ts:1-50]()

Stagehand 的 Handler 架构采用分层设计，上层 CLI 通过 Unix Domain Socket 与本地守护进程通信，守护进程负责维护浏览器会话并执行实际的 DOM 操作。这种设计允许命令行工具、API 和其他客户端共享同一个浏览器实例，同时保持操作的原子性和一致性。Sources: [packages/cli/src/index.ts:200-280]()

## 核心架构

### 组件层次

```
┌─────────────────────────────────────────────────────────────┐
│                      CLI Client                             │
│  (Commands: click, type, hover, fill, screenshot, etc.)    │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  Socket Command Router                      │
│              (runCommand / sendCommand)                     │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Daemon Process                            │
│           (Browser Session Management)                       │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  Handler Execution Layer                     │
│    ┌─────────────┬─────────────┬──────────────────┐        │
│    │ Action      │ Navigation  │ State Check      │        │
│    │ Handlers    │ Handlers    │ Handlers         │        │
│    └─────────────┴─────────────┴──────────────────┘        │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│               Chrome DevTools Protocol (CDP)                │
└─────────────────────────────────────────────────────────────┘
```

### 命令处理流程

当 CLI 收到一个命令（如 `click <selector>`）时，系统按以下流程处理：

```mermaid
graph TD
    A[CLI Command: click] --> B[Parse Options & Arguments]
    B --> C[Call runCommand]
    C --> D[Acquire Session Lock]
    D --> E{Socket Available?}
    E -->|Yes| F[Send Command via Socket]
    E -->|No| G[ensureDaemon]
    G --> F
    F --> H[Daemon Router Switch]
    H --> I[Execute Handler]
    I --> J[CDP: Runtime.evaluate]
    J --> K[Return Result]
    K --> L[Release Lock]
```

Sources: [packages/cli/src/index.ts:300-400]()

## 守护进程管理

### 生命周期管理

Stagehand 使用 Unix Domain Socket 进行进程间通信，并通过文件锁机制确保同一会话的互斥访问：

| 功能 | 实现方式 | 文件路径模式 |
|------|----------|--------------|
| Socket 通信 | Unix Domain Socket | `/tmp/browse-{session}.sock` |
| 进程锁 | O_EXCL 原子文件创建 | `/tmp/browse-{session}.lock` |
| 锁超时 | 10秒默认超时 | - |

Sources: [packages/cli/src/index.ts:250-320]()

### 自动重试机制

命令执行失败时，系统提供智能重试：

| 重试次数 | 策略 | 说明 |
|----------|------|------|
| 0 | 短暂等待 | 200ms 后重试（socket 暂时不可用） |
| 1 | 重启守护进程 | 保持现有文件状态 |
| 2 | 完全清理重启 | 杀死 Chrome 进程并清理残留文件 |

```typescript
// 重试条件判断
const isConnectionError =
  errMsg.includes("ENOENT") ||
  errMsg.includes("ECONNREFUSED") ||
  errMsg.includes("Connection failed");
```

Sources: [packages/cli/src/index.ts:380-420]()

## 操作处理器

### 元素操作命令

| 命令 | 功能 | 关键参数 |
|------|------|----------|
| `click` | 点击元素 | selector, button, clickCount, delay, xpath |
| `dblclick` | 双击元素 | selector, button |
| `hover` | 悬停 | x, y, returnXPath |
| `fill` | 填写输入框 | selector, value, pressEnter |
| `type` | 模拟打字 | text, delay, mistakes |
| `select` | 选择下拉选项 | selector, values |
| `drag` | 拖拽操作 | fromX, fromY, toX, toY |

Sources: [packages/cli/src/index.ts:450-550]()

### 键盘操作

```typescript
program.command("press <key>")
  .alias("key")
  .description("Press key (e.g., Enter, Tab, Escape, Cmd+A)")
```

支持组合键和特殊键位，包括 modifier keys (Cmd, Ctrl, Shift, Alt)。

Sources: [packages/cli/src/index.ts:580-600]()

### 导航操作

| 命令 | 选项 | 默认值 |
|------|------|--------|
| `open <url>` | `--wait` (load/domcontentloaded/networkidle) | load |
| | `-t, --timeout` | 30000ms |
| | `--context-id` | - |
| | `--persist` | false |

Sources: [packages/cli/src/index.ts:620-680]()

## 状态检查处理器

### 元素状态验证

```typescript
program.command("is <check> <selector>")
  .description("Check element state: visible, checked")
```

支持的检查类型：

| 检查类型 | 说明 |
|----------|------|
| `visible` | 元素在视口内可见 |
| `checked` | 复选框/单选框选中状态 |
| `attached` | 元素存在于 DOM |
| `detached` | 元素已从 DOM 移除 |

Sources: [packages/cli/src/index.ts:700-720]()

### 等待机制

```typescript
program.command("wait <type> [arg]")
  .option("-t, --timeout <ms>", "Timeout", "30000")
  .option("-s, --state <state>", "visible, hidden, attached, detached", "visible")
```

| 等待类型 | 参数 | 说明 |
|----------|------|------|
| `load` | - | 页面加载完成 |
| `selector` | CSS 选择器 | 元素出现 |
| `timeout` | 毫秒数 | 自定义超时 |

Sources: [packages/cli/src/index.ts:50-80]()

## 信息获取处理器

### GET 命令

```typescript
program.command("get <what> [selector]")
  .description("Get page info: url, title, text, html, markdown, value, box, visible, checked")
```

| 属性 | 说明 | 返回格式 |
|------|------|----------|
| `url` | 当前页面 URL | string |
| `title` | 页面标题 | string |
| `text` | 元素文本内容 | string |
| `html` | 元素 HTML | string |
| `markdown` | 元素 Markdown | string |
| `value` | 表单元素值 | string |
| `box` | 元素边界框 | {x, y, width, height} |
| `visible` | 可见性状态 | boolean |
| `checked` | 选中状态 | boolean |

Sources: [packages/cli/src/index.ts:720-750]()

## 截图处理器

```typescript
program.command("screenshot [path]")
  .option("-f, --full-page", "Full page screenshot")
  .option("-t, --type <type>", "png, jpeg", "png")
  .option("-q, --quality <n>", "JPEG quality (0-100)")
  .option("--clip <json>", "Clip region")
  .option("--no-animations", "Disable animations")
  .option("--hide-caret", "Hide text caret")
```

Sources: [packages/cli/src/index.ts:750-800]()

## 网络捕获

### 请求/响应记录

系统可以捕获并保存网络请求到文件系统：

```typescript
interface PendingRequest {
  id: string;
  timestamp: string;
  method: string;
  url: string;
  headers: Record<string, string>;
  body: string | null;
  resourceType: string;
}
```

保存目录结构：

```
{networkDir}/
├── 000-GET-example-com-api/
│   ├── request.json
│   └── response.json
└── 001-POST-example-com-login/
    ├── request.json
    └── response.json
```

Sources: [packages/cli/src/index.ts:850-920]()

## 配置与超时

### 全局选项 (GlobalOpts)

```typescript
interface GlobalOpts {
  ws?: string;
  headless?: boolean;
  headed?: boolean;
  json?: boolean;
  session?: string;
  connect?: string;
  // Remote session options
  proxies?: boolean;
  advancedStealth?: boolean;
  solveCaptchas?: boolean;
  region?: string;
  keepAlive?: boolean;
  sessionTimeout?: number;
  blockAds?: boolean;
}
```

### 超时配置

| 操作 | 默认超时 | 配置方式 |
|------|----------|----------|
| 页面导航 | 30000ms | `--timeout` 选项 |
| 截图 | 10000ms | 硬编码 |
| Socket 连接 | 28000ms | `waitForSocketReady` |
| 守护进程锁 | 10000ms | `acquireLock` 参数 |

Sources: [packages/cli/src/index.ts:280-340]()

## 错误处理

### 错误分类

| 错误类型 | 处理策略 | 重试行为 |
|----------|----------|----------|
| ENOENT | 连接错误 | 重试 |
| ECONNREFUSED | 连接错误 | 重试 |
| Connection failed | 连接错误 | 重试 |
| 其他 | 直接抛出 | 不重试 |

```typescript
// 优雅关闭处理
process.on("SIGTERM", () => shutdown());
process.on("SIGINT", () => shutdown());
process.on("uncaughtException", (err) => {
  console.error("Uncaught exception:", err);
  shutdown();
});
```

Sources: [packages/cli/src/index.ts:420-450]()

## 本地浏览器策略

### 策略类型

| 策略 | 说明 | 使用场景 |
|------|------|----------|
| `auto` | 自动检测已存在的浏览器或启动隔离浏览器 | 默认策略 |
| `isolated` | 强制使用独立的 Chrome 实例 | 干净环境 |
| `cdp` | 连接到指定的 CDP 目标 | 调试已有浏览器 |

```typescript
if (localConfig.strategy === "isolated") {
  return {
    localLaunchOptions: { headless, viewport: defaultViewport },
    localInfo: { localSource: "isolated" },
  };
}
```

Sources: [packages/cli/src/local-strategy.ts:1-50]()

### CDP 发现机制

系统通过以下方式发现本地浏览器：

1. 读取 `DevToolsActivePort` 文件获取端口
2. 探测 `/json/version` 端点获取 WebSocket URL
3. 验证端口可达性
4. 建立 WebSocket 连接

```typescript
async function probeJsonVersion(port: number): Promise<string | null> {
  const res = await fetch(`http://127.0.0.1:${port}/json/version`);
  const json = await res.json();
  return json.webSocketDebuggerUrl;
}
```

Sources: [packages/cli/src/local-cdp-discovery.ts:1-100]()

## 会话管理

### 多会话支持

通过 `--session` 参数或 `BROWSE_SESSION` 环境变量指定会话：

```typescript
function getSession(opts: GlobalOpts): string {
  return opts.session ?? process.env.BROWSE_SESSION ?? "default";
}
```

每个会话维护独立的：
- Socket 通信通道
- 浏览器实例
- 状态文件

### 模式覆盖

支持动态切换执行模式（local/remote）：

```typescript
await fs.writeFile(getModeOverridePath(session), mapped);
```

Sources: [packages/cli/src/index.ts:180-220]()

## 参考映射 (Ref Map)

系统缓存最近一次 snapshot 的引用映射，支持 `@ref` 语法：

```typescript
let refMap: {
  xpathMap: Record<string, string>;
  urlMap: Record<string, string>;
} = {
  xpathMap: {},
  urlMap: {},
};

program.command("refs").description("Show cached ref map from last snapshot");
```

Sources: [packages/cli/src/index.ts:820-850]()

## 总结

Handler 处理系统是 Stagehand 实现浏览器自动化的核心抽象层。它通过以下设计原则提供可靠的操作执行：

1. **进程隔离**：守护进程与 CLI 分离，支持多客户端共享
2. **幂等性**：通过锁机制和幂等命令确保安全并发
3. **自动恢复**：智能重试和状态清理保证鲁棒性
4. **灵活配置**：支持多种执行模式和详细参数调优
5. **统一接口**：命令行、API 复用同一 Handler 逻辑

---

<a id='dom-accessibility'></a>

## DOM 与无障碍树

### Related Pages

Related topics: [observe() 页面观察](#observe-api), [Deep Locator 深层定位器](#deep-locator)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
- [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)
- [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)
</details>

# DOM 与无障碍树

## 概述

Stagehand 中的 DOM 与无障碍树（Accessibility Tree，简称 A11y Tree）是核心的页面元素抽象层。该系统将网页的 DOM 结构转换为结构化的无障碍树表示，使 AI 代理能够理解页面内容并执行自动化操作。无障碍树不仅包含元素的可见性信息，还包含语义角色、ARIA 属性和可访问性标签等关键元数据。

Stagehand 通过 `snapshot` 命令获取无障碍树快照，该快照包含格式化的树形结构、元素 XPath 映射和 URL 映射。这些数据被用于元素定位、坐标解析和交互操作。

## 架构设计

### 组件关系

```
graph TD
    A[Browser Page] --> B[DOM Tree]
    A --> C[Accessibility Tree]
    B --> D[snapshot command]
    C --> D
    D --> E[xpathMap]
    D --> F[urlMap]
    D --> G[formattedTree]
    E --> H[Coordinate Resolver]
    F --> I[Element Locator]
    G --> J[AI Agent]
```

### 核心模块

| 模块 | 文件路径 | 职责 |
|------|---------|------|
| A11yTree | `packages/core/lib/v3/understudy/a11y/snapshot/a11yTree.ts` | 无障碍树生成与格式化 |
| DomTree | `packages/core/lib/v3/understudy/a11y/snapshot/domTree.ts` | DOM 树结构处理 |
| CoordinateResolver | `packages/core/lib/v3/understudy/a11y/snapshot/coordinateResolver.ts` | 屏幕坐标解析 |
| FocusSelectors | `packages/core/lib/v3/understudy/a11y/snapshot/focusSelectors.ts` | 焦点元素选择器 |

## Snapshot 命令

### CLI 接口

`packages/cli/src/index.ts` 中定义的 `snapshot` 命令提供两种输出模式：

```typescript
program
  .command("snapshot")
  .description("Get accessibility tree snapshot")
  .option("-c, --compact", "Output tree only (no xpath map)")
  .action(async (cmdOpts) => {
    const result = (await runCommand("snapshot", [cmdOpts.compact])) as {
      tree: string;
      xpathMap?: Record<string, string>;
      urlMap?: Record<string, string>;
    };
    // ...
  });
```

Sources: [packages/cli/src/index.ts:1-500](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

### 输出格式

| 参数 | 类型 | 描述 |
|------|------|------|
| `tree` | `string` | 格式化的无障碍树结构 |
| `xpathMap` | `Record<string, string>` | 元素引用到 XPath 的映射 |
| `urlMap` | `Record<string, string>` | 元素引用到 URL 的映射 |

紧凑模式下仅返回纯文本树结构，适合日志记录和快速调试：

```typescript
if (cmdOpts.compact && !opts.json) {
  console.log(result.tree);
} else {
  output(result, opts.json ?? false);
}
```

## Snapshot 实现

### 后端处理逻辑

在 CLI 的命令处理器中，`snapshot` case 从 Playwright Page 对象获取快照数据：

```typescript
case "snapshot": {
  const [compact] = args as [boolean?];
  const snapshot = await page!.snapshot();

  refMap = {
    xpathMap: snapshot.xpathMap ?? {},
    urlMap: snapshot.urlMap ?? {},
  };

  if (compact) {
    return { tree: snapshot.formattedTree };
  }
  return {
    tree: snapshot.formattedTree,
    xpathMap: snapshot.xpathMap,
    urlMap: snapshot.urlMap,
  };
}
```

Sources: [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

### 引用映射管理

全局 `refMap` 变量存储最新的快照映射，供后续元素操作使用：

```typescript
let refMap: {
  xpathMap: Record<string, string>;
  urlMap: Record<string, string>;
} = {
  xpathMap: {},
  urlMap: {},
};
```

## 元素状态检查

### is 命令

`is` 命令用于检查元素的可访问性状态：

```typescript
case "is": {
  const [check, selector] = args as [string, string];
  const locator = page!.deepLocator(resolveSelector(selector));
  switch (check) {
    case "visible":
      return { visible: await locator.isVisible() };
    case "checked":
      return { checked: await locator.isChecked() };
    default:
      throw new Error(`Unknown check: ${check}`);
  }
}
```

Sources: [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

| 检查类型 | 方法 | 描述 |
|---------|------|------|
| `visible` | `isVisible()` | 元素是否可见 |
| `checked` | `isChecked()` | 复选框/单选框是否选中 |

### CLI 接口

```typescript
program
  .command("is <check> <selector>")
  .description("Check element state: visible, checked")
  .action(async (check: string, selector: string) => {
    const result = await runCommand("is", [check, selector]);
    output(result, opts.json ?? false);
  });
```

## 页面信息获取

### get 命令

`get` 命令提供多种页面和元素信息查询：

```typescript
program
  .command("get <what> [selector]")
  .description(
    "Get page info: url, title, text, html, markdown, value, box, visible, checked",
  )
  .action(async (what: string, selector?: string) => {
    const result = await runCommand("get", [what, selector]);
    output(result, opts.json ?? false);
  });
```

Sources: [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

### 支持的信息类型

| 类型 | 参数 | 返回内容 |
|------|------|---------|
| `url` | 无 | 当前页面 URL |
| `title` | 无 | 页面标题 |
| `text` | selector | 元素文本内容 |
| `html` | selector | 元素 HTML |
| `markdown` | selector | 转换后的 Markdown |
| `value` | selector | 表单元素值 |
| `box` | selector | 元素边界框 {x, y, width, height} |
| `visible` | selector | 元素可见性 |
| `checked` | selector | 复选框状态 |

## 坐标与交互

### 坐标操作命令

| 命令 | 描述 | 选项 |
|------|------|------|
| `click_xy <x> <y>` | 坐标点击 | `--button`, `--count`, `--xpath` |
| `hover <x> <y>` | 坐标悬停 | `--xpath` |
| `scroll <x> <y> <dx> <dy>` | 滚动 | `--xpath` |
| `drag <fromX> <fromY> ...` | 拖拽 | 延迟、坐标选项 |

```typescript
program
  .command("click_xy <x> <y>")
  .description("Click at exact coordinates")
  .option("-b, --button <btn>", "Mouse button: left, right, middle", "left")
  .option("-c, --count <n>", "Click count", "1")
  .option("--xpath", "Return XPath of clicked element")
  .action(async (x: string, y: string, cmdOpts) => {
    const result = await runCommand("click_xy", [
      parseFloat(x),
      parseFloat(y),
      {
        button: cmdOpts.button,
        clickCount: parseInt(cmdOpts.count),
        returnXPath: cmdOpts.xpath,
      },
    ]);
  });
```

Sources: [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

### 坐标解析器

`CoordinateResolver` 模块负责将无障碍树中的元素引用转换为屏幕坐标。该解析器基于快照中的 `xpathMap` 和元素边界框信息计算精确的交互坐标。

## 本地浏览器策略

### 策略类型

`packages/cli/src/local-strategy.ts` 定义了三种本地浏览器连接策略：

```typescript
export async function resolveLocalStrategy({
  localConfig,
  headless,
  defaultViewport,
  discoverLocalCdp,
  resolveWsTarget,
}: ResolveLocalStrategyOptions): Promise<ResolvedLocalStrategy> {
  if (localConfig.strategy === "isolated") {
    return {
      localLaunchOptions: { headless, viewport: defaultViewport },
      localInfo: { localSource: "isolated" },
    };
  }
  // ...
}
```

Sources: [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)

| 策略 | 说明 |
|------|------|
| `isolated` | 启动独立的 Chromium 实例 |
| `cdp` | 连接到指定的 Chrome DevTools Protocol 目标 |
| `auto` | 自动检测本地调试端口 |

### CDP 发现机制

`packages/cli/src/local-cdp-discovery.ts` 实现了自动发现本地 Chrome 调试端口的功能：

```typescript
async function resolveDevToolsActivePortUrl(
  port: number,
  userDataDirs: string[],
): Promise<string | null> {
  for (const dir of userDataDirs) {
    const info = await readDevToolsActivePort(dir);
    if (!info || info.port !== port) {
      continue;
    }
    // 验证端口可达性
    if (!(await isPortReachable(info.port))) {
      await cleanupStaleDevToolsActivePort(dir);
      continue;
    }
    return buildDevToolsWsUrl(info.port, info.wsPath);
  }
  return null;
}
```

Sources: [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)

## 网络捕获集成

### 快照与网络数据

无障碍树快照可以与网络捕获功能结合使用：

```typescript
interface PendingRequest {
  id: string;
  timestamp: string;
  method: string;
  url: string;
  headers: Record<string, string>;
  body: string | null;
  resourceType: string;
}
```

每个网络请求保存到文件系统时，使用 URL 解析生成目录名：

```typescript
function getRequestDirName(
  counter: number,
  method: string,
  url: string,
): string {
  try {
    const parsed = new URL(url);
    const domain = sanitizeForFilename(parsed.hostname, 30);
    const pathPart = parsed.pathname.split("/").filter(Boolean)[0] || "root";
    const pathSlug = sanitizeForFilename(pathPart, 20);
    return `${String(counter).padStart(3, "0")}-${method}-${domain}-${pathSlug}`;
  } catch {
    return `${String(counter).padStart(3, "0")}-${method}-unknown`;
  }
}
```

Sources: [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)

## 使用场景

### 基本工作流程

```mermaid
graph LR
    A[open <url>] --> B[snapshot]
    B --> C[xpathMap + urlMap]
    C --> D[click <element>]
    D --> E[verify state]
    E --> F[screenshot]
```

### 多页面管理

Stagehand 支持多标签页操作：

```typescript
program
  .command("pages")
  .description("List all open pages")
  .action(async () => {
    const result = await runCommand("pages", []);
    output(result, opts.json ?? false);
  });

program
  .command("tab_close [index]")
  .alias("close")
  .description("Close tab by index (defaults to last tab)")
  .action(async (index?: string) => {
    const result = await runCommand("tab_close", [
      index ? parseInt(index) : undefined,
    ]);
    output(result, opts.json ?? false);
  });
```

## 总结

DOM 与无障碍树系统是 Stagehand 实现浏览器自动化的基础。通过将复杂 DOM 结构转换为语义化的无障碍树，结合 XPath 映射和坐标解析，AI 代理能够准确理解和操作网页元素。该系统与 CLI 工具深度集成，提供 `snapshot`、`get`、`is` 等命令支持灵活的页面检查和交互操作。

---

<a id='deep-locator'></a>

## Deep Locator 深层定位器

### Related Pages

Related topics: [DOM 与无障碍树](#dom-accessibility), [act() 操作执行](#act-api)

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/cli/src/index.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/index.ts)
- [packages/cli/src/local-strategy.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-strategy.ts)
- [packages/cli/src/local-cdp-discovery.ts](https://github.com/browserbase/stagehand/blob/main/packages/cli/src/local-cdp-discovery.ts)
</details>

# Deep Locator 深层定位器

## 概述

Deep Locator（深层定位器）是 Stagehand 框架中负责精确定位和操作 DOM 元素的核心子系统。它通过多层次的定位策略、跨帧（iframe）处理、以及智能选择器解析，实现了对复杂网页结构中元素的可靠访问。该系统是 Stagehand 能够实现高精度自动化控制的关键技术基础。

**核心职责：**

- 提供多种元素定位策略（CSS 选择器、XPath、坐标等）
- 处理跨 iframe/跨帧的元素定位
- 管理浏览器上下文和帧的注册与追踪
- 解析和优化选择器以提高定位准确性
- 与 CLI 命令层紧密集成，支持交互式定位操作

Sources: [packages/cli/src/index.ts:1-50]()

---

## 架构组件

Deep Locator 系统由以下核心组件构成，它们协同工作以实现端到端的元素定位能力：

| 组件名称 | 文件路径 | 主要职责 |
|---------|---------|---------|
| DeepLocator | `packages/core/lib/v3/understudy/deepLocator.ts` | 主定位引擎，整合多种定位策略 |
| Piercer | `packages/core/lib/v3/understudy/piercer.ts` | 处理 iframe 穿透和跨帧定位 |
| FrameRegistry | `packages/core/lib/v3/understudy/frameRegistry.ts` | 管理帧层级结构和状态 |
| SelectorResolver | `packages/core/lib/v3/understudy/selectorResolver.ts` | 选择器解析和优化 |

Sources: [packages/cli/src/index.ts:50-80]()

### 组件关系图

```mermaid
graph TD
    A[CLI Command] --> B[DeepLocator]
    B --> C[SelectorResolver]
    B --> D[Piercer]
    D --> E[FrameRegistry]
    E --> F[Browser CDP]
    C --> F
    F --> B
```

---

## 定位策略

Stagehand 的 Deep Locator 支持多种定位策略，适用于不同的场景需求：

### 基础定位命令

| 命令 | 用途 | 典型用法 |
|-----|------|---------|
| `click` | 点击元素 | `click <selector> [options]` |
| `hover` | 悬停元素/坐标 | `hover <x> <y> [--xpath]` |
| `fill` | 填写表单输入 | `fill <selector> <value>` |
| `type` | 模拟打字输入 | `type <text> [--delay] [--mistakes]` |
| `select` | 选择下拉选项 | `select <selector> <values...>` |

Sources: [packages/cli/src/index.ts:200-280]()

### 坐标操作

对于无法通过选择器精确定位的场景，系统支持基于坐标的操作：

```typescript
program
  .command("scroll <x> <y> <deltaX> <deltaY>")
  .description("Scroll at coordinates")
  .option("--xpath", "Return XPath of scrolled element")
```

### 元素状态检查

在执行操作前，系统允许检查元素状态以确保操作安全：

| 检查类型 | 说明 |
|---------|------|
| `visible` | 元素是否可见 |
| `checked` | 复选框/单选框是否选中 |
| `attached` | 元素是否在 DOM 中 |
| `detached` | 元素是否已从 DOM 移除 |

Sources: [packages/cli/src/index.ts:180-200]()

---

## 帧（Frame）管理

Deep Locator 的一个关键特性是能够处理嵌套的 iframe 结构。FrameRegistry 组件维护了一个帧层级注册表。

### 本地策略解析

系统通过 `resolveLocalStrategy` 函数管理本地浏览器实例的帧发现：

```typescript
export async function resolveLocalStrategy({
  localConfig,
  headless,
  defaultViewport,
  discoverLocalCdp,
  resolveWsTarget,
}: ResolveLocalStrategyOptions): Promise<ResolvedLocalStrategy>
```

**支持的三种本地策略：**

| 策略 | 描述 | 使用场景 |
|-----|------|---------|
| `isolated` | 启动独立 Chromium 实例 | 完全隔离的测试环境 |
| `cdp` | 连接到已有 Chrome DevTools | 附加到正在运行的浏览器 |
| `auto` | 自动检测可用浏览器 | 灵活适配不同环境 |

Sources: [packages/cli/src/local-strategy.ts:30-80]()

### CDP 发现机制

系统通过 `discoverLocalCdp` 函数自动发现可用的 Chrome DevTools Protocol 端点：

```mermaid
graph LR
    A[Scan Chrome Profile Dirs] --> B[Read DevToolsActivePort]
    B --> C{Port Reachable?}
    C -->|Yes| D[Build WebSocket URL]
    C -->|No| E[Cleanup Stale File]
    D --> F[Return wsUrl]
    E --> A
```

Sources: [packages/cli/src/local-cdp-discovery.ts:50-100]()

---

## 选择器解析器

SelectorResolver 负责将人类可读的选择器表达式转换为高效的浏览器指令：

### 选择器类型支持

| 类型 | 示例 | 优先级 |
|-----|------|-------|
| CSS 选择器 | `#id`, `.class`, `div[data-*]` | 高 |
| XPath | `//div[@class='target']` | 中 |
| 文本匹配 | `text="登录"` | 中 |
| 混合表达式 | `button:text("提交")` | 中 |

### 优化策略

系统会智能优化选择器以提高性能：

1. **缓存机制** - 缓存最近使用的选择器结果
2. **批量查询** - 合并多个选择器请求
3. **超时控制** - 防止单个选择器阻塞整个流程

---

## 网络捕获与调试

Deep Locator 集成网络捕获功能，便于调试定位问题：

### 网络请求状态管理

```typescript
interface PendingRequest {
  id: string;
  timestamp: string;
  method: string;
  url: string;
  headers: Record<string, string>;
  body: string | null;
  resourceType: string;
}
```

Sources: [packages/cli/src/index.ts:15-30]()

### 文件系统写入

每个捕获的请求都会写入独立的目录结构：

```
network-capture/
├── 001-GET-api.example.com/users
│   ├── request.json
│   └── response.json
└── 002-POST-api.example.com/login
    ├── request.json
    └── response.json
```

**目录命名规范：**

```typescript
function getRequestDirName(
  counter: number,
  method: string,
  url: string,
): string {
  const parsed = new URL(url);
  const domain = sanitizeForFilename(parsed.hostname, 30);
  const pathPart = parsed.pathname.split("/").filter(Boolean)[0] || "root";
  const pathSlug = sanitizeForFilename(pathPart, 20);
  return `${String(counter).padStart(3, "0")}-${method}-${domain}-${pathSlug}`;
}
```

Sources: [packages/cli/src/index.ts:40-60]()

---

## 守护进程基础设施

Deep Locator 使用 Unix Socket 通信实现高效的守护进程模式：

### 锁机制

```mermaid
graph TD
    A[Acquire Lock] --> B{File Exists?}
    B -->|No| C[Create Lock File]
    B -->|Yes| D{Process Alive?}
    D -->|Yes| E[Wait 100ms]
    D -->|No| F[Remove Stale Lock]
    E --> B
    C --> G[Lock Acquired]
    F --> B
```

**关键特性：**

- 使用 `O_EXCL` 确保原子性文件创建
- 检测僵尸进程并自动清理过期锁
- 可配置超时机制（默认 10000ms）

Sources: [packages/cli/src/index.ts:280-320]()

### Socket 路径管理

```typescript
const SOCKET_DIR = os.tmpdir();

function getSocketPath(session: string): string {
  return path.join(SOCKET_DIR, `browse-${session}.sock`);
}

function getLockPath(session: string): string {
  return path.join(SOCKET_DIR, `browse-${session}.lock`);
}
```

---

## CLI 命令参考

### 基础导航

```bash
# 打开 URL
browse open <url> [--wait load|domcontentloaded|networkidle] [-t timeout]
browse goto <url>  # alias

# 创建新页面
browse newpage [url]

# 页面信息
browse get <what> [selector]  # url|title|text|html|markdown|value|box
```

### 元素操作

```bash
# 点击
browse click <selector> [-d delay] [-x|--xpath]

# 输入
browse fill <selector> <value> [--no-press-enter]
browse type <text> [-d delay] [--mistakes]

# 键盘
browse press <key>  # Enter, Tab, Escape, Cmd+A, etc.
```

### 截图功能

```bash
browse screenshot [path]
  [--full-page]           # 整页截图
  [--type png|jpeg]       # 图片格式
  [--quality 0-100]       # JPEG 质量
  [--clip <json>]         # 裁剪区域
  [--no-animations]       # 禁用动画
  [--hide-caret]          # 隐藏文本光标
```

Sources: [packages/cli/src/index.ts:350-400]()

---

## 配置选项

### 全局选项

| 选项 | 类型 | 说明 |
|-----|------|------|
| `--headless` | boolean | 无头模式运行 |
| `--headed` | boolean | 显示浏览器窗口 |
| `--json` | boolean | JSON 格式输出 |
| `--session` | string | 会话标识符 |
| `--connect` | string | 连接远程浏览器 |
| `--ws` | string | WebSocket 地址 |

### 远程会话选项

| 选项 | 说明 |
|-----|------|
| `--proxies` | 启用代理支持 |
| `--advanced-stealth` | 高级反检测 |
| `--solve-captchas` | 自动解决验证码 |
| `--region` | 区域设置 |
| `--keep-alive` | 保持连接活跃 |
| `--session-timeout` | 会话超时秒数 |
| `--block-ads` | 拦截广告 |

Sources: [packages/cli/src/index.ts:400-450]()

---

## 工作流程图

```mermaid
sequenceDiagram
    participant CLI
    participant DeepLocator
    participant SelectorResolver
    participant FrameRegistry
    participant CDP

    CLI->>DeepLocator: locate(element)
    DeepLocator->>SelectorResolver: resolve(selector)
    SelectorResolver->>CDP: query()
    CDP-->>SelectorResolver: elements[]
    SelectorResolver-->>DeepLocator: resolved
    DeepLocator->>FrameRegistry: checkFrame(element)
    FrameRegistry->>CDP: switchContext()
    CDP-->>FrameRegistry: context
    FrameRegistry-->>DeepLocator: frameContext
    DeepLocator-->>CLI: result
```

---

## 最佳实践

1. **选择器优先级** - 优先使用 ID 选择器，其次是 data 属性，避免过度依赖 XPath
2. **等待策略** - 使用显式等待（`wait` 命令）而非固定延迟
3. **帧切换** - 跨帧操作前务必使用 `FrameRegistry` 进行上下文切换
4. **网络调试** - 定位问题时启用网络捕获功能分析请求流
5. **截图验证** - 使用 `--hide-caret` 和 `--no-animations` 获取稳定截图

---

---

## Doramagic 踩坑日志

项目：browserbase/stagehand

摘要：发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：身份坑 - 仓库名和安装名不一致。

## 1. 身份坑 · 仓库名和安装名不一致

- 严重度：medium
- 证据强度：runtime_trace
- 发现：仓库名 `stagehand` 与安装入口 `create-browser-app` 不完全一致。
- 对用户的影响：用户照着仓库名搜索包或照着包名找仓库时容易走错入口。
- 建议检查：在 npm/PyPI/GitHub 上确认包名映射和官方 README 说明。
- 复现命令：`npx create-browser-app`
- 防护动作：页面必须同时展示 repo 名和真实安装入口，避免用户搜索错包。
- 证据：identity.distribution | github_repo:776908852 | https://github.com/browserbase/stagehand | repo=stagehand; install=create-browser-app

## 2. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | github_repo:776908852 | https://github.com/browserbase/stagehand | README/documentation is current enough for a first validation pass.

## 3. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | github_repo:776908852 | https://github.com/browserbase/stagehand | last_activity_observed missing

## 4. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | github_repo:776908852 | https://github.com/browserbase/stagehand | no_demo; severity=medium

## 5. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | github_repo:776908852 | https://github.com/browserbase/stagehand | no_demo; severity=medium

## 6. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | github_repo:776908852 | https://github.com/browserbase/stagehand | issue_or_pr_quality=unknown

## 7. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：evidence.maintainer_signals | github_repo:776908852 | https://github.com/browserbase/stagehand | release_recency=unknown

<!-- canonical_name: browserbase/stagehand; human_manual_source: deepwiki_human_wiki -->
