mirror of
https://git.openapi.site/https://github.com/desirecore/market.git
synced 2026-09-06 17:23:56 +08:00
feat(web-access): 恢复 L3-external——两个浏览器由用户意图选,而非能力难度选 (#87)
## 背景 / Background v3.0(#85)以「它存在的每一条技术理由(无批量取文通道、evaluate 不可用、截图必须串行 activate)都已被内置浏览器覆盖」为由,删除了 Python Playwright 那一层。 **作为「内置浏览器不够用时的兜底」,这个判断是对的。** 但删除时顺带丢掉了一个完全不同的用例:用户想用**他自己那个**浏览器——他的登录态在他自己的 Chrome 里,他想亲眼看着操作、随时接管。这跟能力够不够无关,内置浏览器替代不了。 真实案例:用户要求「请你操作我本地机器的外部浏览器来完成一个示例报关过程」。技能里已无此路径,模型自己也查出「无独立的 Browser* 外部浏览器工具」,仍用内置浏览器做完全程,并以「本地受管浏览器」「已启动本地浏览器」描述——用户拿到的和要的不是一回事,却无从分辨。 v3.0 (#85) removed the Python Playwright layer on the grounds that every technical reason it existed for is now covered by the built-in browser. **As a fallback, that judgement was right.** But the deletion also took a different use case with it: the user wanting *their own* browser — their login state, their window, theirs to watch and take over. That has nothing to do with capability, and the built-in browser cannot stand in for it. ## 改动 / Changes 把 L3-external 作为**由用户意图触发的平级选择**恢复(**不再是 fallback**): - 恢复 `references/cdp-browser.md`(v3.0 删除,含 `connect_over_cdp` 模板与站点配方) - 恢复 `Prerequisites: Chrome CDP Setup`,重新定位为「**仅 L3-external 需要**」,内置浏览器仍零前置条件 - 决策树的实时交互分支改为双路:用户点名外部 → L3-external;其余 → 内置(默认) - 新增「两个浏览器,按用户意图选」对照表:是什么 / 登录态 / 用户能否看到 / 前置条件 / 是否默认 - 分层表加回 L3-external,并说明它**刻意不在默认排序里**——判据是用户点名,不是能力够不够 - 明确:CDP attach 时严禁 `browser.close()`(会关掉用户自己的 Chrome) - 无论走哪条,措辞必须让用户能分辨实际用了哪个;禁止「本地浏览器」这类两边都像的说法 version 3.0.1 → 3.2.0 ## 校验 / Validation - `python3 scripts/i18n/validate-i18n.py` → OK: no i18n issues found - `python3 scripts/i18n/translate.py --check` → web-access en-US `human-locked, skipping`(无 source_hash 漂移) - 双语同步;en-US 为 human-locked 翻译,已手工同步并按 `compute_source_hash` 重算对齐 ## 公开信息边界 / Public information boundary 改动仅涉及浏览器能力边界的技术描述,无租户、客户或其他机密身份信息。 --------- Co-authored-by: Yige <a@wyr.me>
This commit is contained in:
@@ -5,17 +5,17 @@ description: >-
|
||||
— searching for current information, fetching public web pages, browsing
|
||||
login-gated sites (微博/小红书/B站/飞书/Twitter), comparing products,
|
||||
researching topics, gathering documentation, or summarizing news.
|
||||
This skill orchestrates three complementary layers: (1) WebSearch + WebFetch
|
||||
This skill orchestrates four complementary layers: (1) WebSearch + WebFetch
|
||||
for public pages, (2) Jina Reader as the default token-optimization layer for
|
||||
heavy/JS-rendered pages, and (3) the governed built-in browser (isolated
|
||||
BrowserSpace + Cookie import + bulk text extraction + waits + code mode) to
|
||||
reach, interact with, and read login-gated sites. Always cite source URLs.
|
||||
reach, interact with, and read login-gated sites, and (4) the user's own Chrome over CDP when they ask for it by name. Always cite source URLs.
|
||||
Use when 用户提到 联网搜索、上网查、
|
||||
查资料、抓取网页、研究、调研、最新资讯、文档查询、对比、竞品、技术文档、
|
||||
新闻、网址、URL、找一下、搜一下、查一下、小红书、B站、微博、飞书、Twitter、
|
||||
推特、X、知乎、公众号、已登录、登录状态。
|
||||
license: Complete terms in LICENSE.txt
|
||||
version: 3.0.1
|
||||
version: 3.2.0
|
||||
type: procedural
|
||||
risk_level: low
|
||||
status: enabled
|
||||
@@ -41,7 +41,7 @@ provides:
|
||||
- LocalBookmarks
|
||||
metadata:
|
||||
author: desirecore
|
||||
updated_at: '2026-08-18'
|
||||
updated_at: '2026-08-21'
|
||||
i18n:
|
||||
default_locale: en-US
|
||||
source_locale: zh-CN
|
||||
@@ -51,16 +51,16 @@ metadata:
|
||||
zh-CN:
|
||||
name: 联网访问
|
||||
short_desc: 联网搜索、网页抓取、内置受管浏览器登录态访问与取文、研究调研工作流
|
||||
description: 三层联网访问工具包——搜索公开页面、Jina 优化抓取、内置受管浏览器完成登录态访问、交互与取文。
|
||||
description: 联网访问工具包——搜索公开页面、Jina 优化抓取、内置受管浏览器完成登录态访问与取文,以及用户点名时接管他自己的 Chrome。
|
||||
body: ./SKILL.zh-CN.md
|
||||
source_hash: sha256:20c98f047378220a
|
||||
source_hash: sha256:4d3bc4221b2d6b09
|
||||
translated_by: human
|
||||
en-US:
|
||||
name: Web Access
|
||||
short_desc: Web search, page fetching, logged-in access via the governed built-in browser, research workflows
|
||||
description: A three-layer web-access toolkit — search public pages, fetch heavy pages via Jina Reader, and reach, interact with, and read logged-in sites through the governed built-in browser.
|
||||
description: A web-access toolkit — search public pages, fetch heavy pages via Jina Reader, reach and read logged-in sites through the governed built-in browser, and drive the user's own Chrome over CDP on request.
|
||||
body: ./SKILL.md
|
||||
source_hash: sha256:20c98f047378220a
|
||||
source_hash: sha256:4d3bc4221b2d6b09
|
||||
translated_by: human
|
||||
market:
|
||||
icon: >-
|
||||
@@ -89,19 +89,21 @@ market:
|
||||
|
||||
## L0: One-line Summary
|
||||
|
||||
A three-layer web-access toolkit — search public pages, optimize fetches via Jina Reader, and reach, interact with, and read login-gated sites through the governed built-in browser (v3.0 ships bulk text extraction, waits, and code mode in-browser; the Python Playwright fallback is gone).
|
||||
A web-access toolkit — search public pages, optimize fetches via Jina Reader, reach/interact with/read login-gated sites through the governed built-in browser, and drive the user's own Chrome over CDP when they ask for it by name.
|
||||
|
||||
## L1: Overview & Use Cases
|
||||
|
||||
### Capability
|
||||
|
||||
web-access is a **procedural skill** that provides three complementary layers of web access:
|
||||
web-access is a **procedural skill** that provides four complementary layers of web access:
|
||||
|
||||
- **L1** (WebSearch + WebFetch): public, static pages
|
||||
- **L2** (Jina Reader): JS-rendered heavy pages, saving tokens by default
|
||||
- **L3** (governed built-in browser, capability surface completed in v3.0): reach, *interact with*, and **read** logged-in / interactive sites — isolated BrowserSpace per task, zero Python dependency, every action carries a signed receipt. Bulk text extraction (`page.extract-text`), discriminated waits (`page.wait`), and code mode (`BrowserScript`) all close the loop inside this layer
|
||||
|
||||
The v2.x fourth layer — "user manually launches a debug Chrome + Python Playwright CDP" — was removed in v3.0: every reason it existed for (no bulk text channel, evaluate unusable, screenshots must activate-serialize) is now covered by the built-in browser, see the cheatsheet below.
|
||||
- **L3-external** (the user's own Chrome, attached via CDP + Python Playwright): **take this route when the user names their own browser** — their login state, their window, visible to them the whole time and theirs to take over at any moment
|
||||
|
||||
A note of history on L3-external: v3.0 deleted it outright, on the grounds that "every technical reason it existed for (no bulk text channel, evaluate unusable, screenshots must activate-serialize) is now covered by the built-in browser". That technical judgement was correct — **as a fallback for when the built-in browser isn't enough, it genuinely isn't needed any more**. But the deletion took with it a completely different use case: the user wanting *their own* browser. That has nothing to do with capability, and the built-in browser cannot stand in for it, so v3.2 restores it as a peer option **triggered by user intent**. Note it is no longer a fallback; see "Two browsers — pick by user intent" below.
|
||||
|
||||
### v3.0: governed built-in browser (default-hidden, exposed only after Skill activation)
|
||||
|
||||
@@ -132,10 +134,10 @@ When you call `Skill('web-access')`, the following 9 tools are injected into the
|
||||
|
||||
### Core Value
|
||||
|
||||
- **Three-layer progression**: from lightweight search to heavy JS rendering to logged-in access — pick on demand
|
||||
- **Layered progression**: from lightweight search to heavy JS rendering to logged-in access — pick on demand; plus the user's own browser whenever they name it
|
||||
- **Token optimization**: Jina Reader cuts token usage by 50–80% by default; `page.extract-text`'s maxBytes/cursor paging keeps even long logged-in articles under control
|
||||
- **Logged-in session reuse**: where the Host has granted `browser.import.*`, BrowserImport brings the user's Cookies into an isolated Space — no re-login required
|
||||
- **Zero external dependencies**: no Python/Playwright install, no manually launched debug Chrome
|
||||
- **Zero external dependencies by default**: the built-in browser needs no Python/Playwright install and no manually launched debug Chrome (L3-external does, and only when the user asks for it)
|
||||
|
||||
## L2: Detailed Specification
|
||||
|
||||
@@ -147,6 +149,55 @@ When you complete a research task, you **MUST** cite all source URLs in your res
|
||||
|
||||
If any fetch fails, explicitly tell the user which URL failed and which fallback you used.
|
||||
|
||||
## Prerequisites: Chrome CDP Setup (L3-external only)
|
||||
|
||||
**Only needed when taking the L3-external route** (the user named their own browser). The built-in
|
||||
browser has no prerequisites.
|
||||
|
||||
### One-time setup
|
||||
|
||||
Have the user launch Chrome with remote debugging enabled:
|
||||
|
||||
**macOS**:
|
||||
```bash
|
||||
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
|
||||
--remote-debugging-port=9222 \
|
||||
--user-data-dir="${DESIRECORE_ROOT}/chrome-profile"
|
||||
```
|
||||
|
||||
**Linux**:
|
||||
```bash
|
||||
google-chrome \
|
||||
--remote-debugging-port=9222 \
|
||||
--user-data-dir="${DESIRECORE_ROOT}/chrome-profile"
|
||||
```
|
||||
|
||||
**Windows (PowerShell)**:
|
||||
```powershell
|
||||
& "C:\Program Files\Google\Chrome\Application\chrome.exe" `
|
||||
--remote-debugging-port=9222 `
|
||||
--user-data-dir="$env:USERPROFILE\.desirecore\chrome-profile"
|
||||
```
|
||||
|
||||
After launch:
|
||||
1. The user logs in manually to the sites they need
|
||||
2. That Chrome window stays open
|
||||
3. Verify the debug endpoint: `curl -s http://localhost:9222/json/version` should return JSON
|
||||
|
||||
### Verify readiness before every operation
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:9222/json/version | python3 -c "import sys,json; d=json.load(sys.stdin); print('CDP ready:', d.get('Browser'))"
|
||||
```
|
||||
|
||||
If it fails, tell the user: "请先启动 Chrome 并开启远程调试端口(见 web-access 技能的 Prerequisites 部分)"
|
||||
— **then wait for them.** Don't switch to the built-in browser just because it could also do the job.
|
||||
|
||||
⚠️ When attached over CDP, **never call `browser.close()`** — that would close the user's own Chrome.
|
||||
Only close the page you opened. Full recipes in [references/cdp-browser.md](references/cdp-browser.md).
|
||||
|
||||
---
|
||||
|
||||
## Tool Selection Decision Tree
|
||||
|
||||
```
|
||||
@@ -177,20 +228,66 @@ User intent
|
||||
│ - PyPI: curl https://pypi.org/pypi/<pkg>/json
|
||||
│
|
||||
└─ "Real-time interactive task" (click, fill form, scroll, screenshot)
|
||||
└─→ built-in browser (BrowserManage → BrowserAct → BrowserSnapshot —
|
||||
├─→ **User named "my own / my machine's / the external browser"** → L3-external:
|
||||
│ verify CDP is ready (see Prerequisites), then python3 playwright.connect_over_cdp()
|
||||
│ If it isn't ready, give them the launch command and wait — don't quietly switch to the built-in one
|
||||
└─→ **Otherwise (default)**: built-in browser (BrowserManage → BrowserAct → BrowserSnapshot —
|
||||
see references/browser-tools.md, no Python needed)
|
||||
```
|
||||
|
||||
### Three-layer strategy summary
|
||||
### Two browsers — pick by user intent, not by difficulty
|
||||
|
||||
DesireCore can drive **two** browsers. They are peer options:
|
||||
|
||||
| | L3 built-in governed browser | L3-external — the user's own browser |
|
||||
|---|---|---|
|
||||
| What it is | A browser instance inside the app (the `Browser*` tools) | The Chrome installed on the user's machine, attached via CDP + Python Playwright |
|
||||
| Login state | Isolated; needs `browser.import.*` granted by the Host before `BrowserImport` can pull cookies | **Literally the user's own session** — nothing to import |
|
||||
| Can the user see it | Agent tabs are offscreen by default; must be presented to the workbench | **It's their own window** — visible throughout, theirs to take over |
|
||||
| Prerequisite | None | User must launch Chrome with `--remote-debugging-port=9222` (see Prerequisites) |
|
||||
| Default | ✅ yes | When the user names it |
|
||||
|
||||
> The login-state row is easy to misread as "the built-in browser can't reuse the user's login
|
||||
> state" — that isn't what it says. Precisely: it **can't reuse it directly**. `Browser*` cannot see
|
||||
> the windows or tabs of the user's external browser and cannot read its live session; but once the
|
||||
> Host grants `browser.import.*`, `BrowserImport` can carry that login state into an isolated Space
|
||||
> **by importing cookies**. The distinction is "take over that live session" (not possible) versus
|
||||
> "import a copy of the cookies" (possible, once authorized). Only without that grant is the login
|
||||
> state genuinely unreusable — and then you say so plainly.
|
||||
|
||||
**The layer is chosen by user intent, not by technical difficulty.** v3.0 deleted this layer as
|
||||
"a fallback for when the built-in browser isn't enough" — and as a fallback, it really isn't needed
|
||||
any more. But that deletion also removed a **different** use case: the user wanting *their own*
|
||||
browser. That has nothing to do with capability — their login state lives in their Chrome, and they
|
||||
want to watch it happen and take over when they choose. The built-in browser cannot stand in for that.
|
||||
|
||||
**If the user named one, use the one they named:**
|
||||
|
||||
- "my own / my machine's / the external browser / my Chrome" → **L3-external**. Verify CDP readiness
|
||||
per Prerequisites first; if it isn't ready, give them the launch command and wait. **Do not switch
|
||||
to the built-in browser just because it could also do the job**
|
||||
- "the built-in browser", or nothing named → **L3 built-in** (default, no prerequisites)
|
||||
- Genuinely unclear which they mean → ask, don't guess
|
||||
|
||||
⚠️ Either way, the user must be able to tell which one you actually used. Never use wording that fits
|
||||
both — "the local browser", "the managed browser on your machine", "your local browser is now open".
|
||||
When what they asked for and what you're giving differ, the wording has to make that visible.
|
||||
|
||||
### Layer strategy summary
|
||||
|
||||
| Layer | Use case | Primary tool | Token cost |
|
||||
|-------|----------|--------------|------------|
|
||||
| L1 | Public, static | `WebFetch` | Low |
|
||||
| L2 | JS-heavy, long articles, token savings | `Bash curl r.jina.ai` | **Lowest** (Markdown pre-cleaned) |
|
||||
| **L3** | **Login-gated navigation, interaction & extraction (PRIMARY)** | **built-in browser (BrowserManage / BrowserAct / BrowserSnapshot / BrowserScript)** | Medium |
|
||||
| L3-external | **User named their own browser**; or their personal login state is needed and `BrowserImport` is unavailable | `Bash + Python Playwright connect_over_cdp` (see references/cdp-browser.md) | Medium |
|
||||
|
||||
**Default priority**: L1 for simple public pages → L2 for heavy → **L3 for login-gated (body text and in-site API data included)**.
|
||||
|
||||
|
||||
> L3-external is deliberately absent from this ordering: it isn't chosen by "is the layer capable
|
||||
> enough" but by **the user naming it**. When the user wants their own browser, go there directly —
|
||||
> even if the built-in browser could do the job. See "Two browsers — pick by user intent" above.
|
||||
## Supported Sites Matrix
|
||||
|
||||
| Site | Recommended Layer | Notes |
|
||||
|
||||
Reference in New Issue
Block a user