# 为什么做共享真实浏览器

## 问题

LLM agent 需要"上网"。传统做法是给 agent 一个**无头浏览器**(Playwright/Puppeteer 等)或**网页抓取工具**:

- 无头浏览器:agent 在看不见的页面里操作,用户无法确认它在做什么,也无法中途接管;遇到登录、验证码、人机检测时寸步难行。
- 网页抓取:只能读不能交互,且大量现代网站依赖 JS 渲染,抓到的内容失真。

这两条路都绕开了"用户"——浏览器成了 agent 的私有工具,而不是用户和 agent 共用的工具。

## 方案:共享真实浏览器

`dsh-builtin-browser` 的思路很朴素:**让 agent 驱动用户眼前那个真实的浏览器窗口**。

- 浏览器是原生 `WebContentsView`,用户直接看到 agent 的每一步操作(打开页面、填写表单、点击、滚动);
- 用户**随时可以上手接管**:输入、点击、登录、过验证码——做完之后 agent 继续;
- agent 通过 CDP 在同一个页面里执行 JS,拿到的是与用户所见完全一致的真实 DOM。

一句话:浏览器不是 agent 的"黑盒工具",而是**用户与 agent 之间的共享工作台**。

## 与无头方案的能力对比

| 能力 | 无头浏览器 | 网页抓取 | 本插件(共享真实浏览器) |
| --- | --- | --- | --- |
| 真实页面渲染 | ✅ | 部分 | ✅ |
| 复杂交互(填表/点击/拖拽) | ✅ | ❌ | ✅ |
| 用户可见、可接管 | ❌ | ❌ | ✅ |
| 保留登录态 | 需手动管理 | ❌ | ✅(`browser_auth` + cookie 落盘) |
| 人工处理验证码 | ❌ 卡死 | ❌ | ✅ 请用户点一下即可 |
| 多任务并行 | 需多实例 | – | ✅ 任务级会话隔离 |

## 设计取舍

- **登录态共享**:所有任务共享同一份 cookie(符合"用户登录一次,agent 到处可用");需要隔离时用 `browser_auth` 手动导出/恢复。
- **任务级会话隔离**:每个 DSH 会话(任务)拥有独立的浏览器会话(标签页与历史),并发任务互不抢页面;但窗口只有一个,当前活动的任务视图可见。
- **装好即用**:不依赖桌面外壳。有外壳时嵌入外壳视图;纯 `dsh web` 时插件自托管——自己拉起 Electron 窗口,通过本机 TCP JSON-RPC 驱动。
- **边界清晰**:可见视图、浏览器列布局属于宿主外壳;插件只负责 seam、provider 与工具,不含任何 UI。
- **人机验证不硬刚**:检测到 Cloudflare/reCAPTCHA/hCaptcha/Turnstile 时停下,请用户在共享窗口人工完成,而不是盲目重试。

## 什么场景不适合

- 需要**无头批量抓取**(成千上万页面):请用专门的抓取工具/服务,不必开窗口。
- 需要**每个任务完全独立的登录态**(互不可见):本插件默认共享 cookie;如需强隔离,可用多个 DSH 实例或 `browser_auth` 手动管理。
- 需要**浏览器列 UI / 布局管理**:那是宿主外壳的配套,本插件不包含。
