web-access-cli 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -262
- package/README_CN.md +104 -264
- package/dist/gateway/admin.js +670 -0
- package/dist/gateway/admin.js.map +1 -0
- package/dist/gateway/panel.js +1741 -127
- package/dist/gateway/panel.js.map +1 -1
- package/dist/gateway/records.js +384 -7
- package/dist/gateway/records.js.map +1 -1
- package/dist/gateway/server.js +270 -104
- package/dist/gateway/server.js.map +1 -1
- package/dist/gateway/service.js +243 -53
- package/dist/gateway/service.js.map +1 -1
- package/dist/providers/xai.js +16 -8
- package/dist/providers/xai.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README_CN.md
CHANGED
|
@@ -5,334 +5,174 @@
|
|
|
5
5
|
[](https://github.com/Juexe/web-access-cli/actions/workflows/ci.yml)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
同一核心上的两个入口:面向直接调用的 **CLI**,以及面向常驻 Agent 运行时的 **DeepSeek 兼容 HTTP 网关**。两者都提供搜索与正文提取两项能力,把 Tavily、Exa、Bocha、元宝搜索、Brave、SearXNG、AnySearch、XCrawl、DeepSeek、Firecrawl、Jina 等差异收敛到同一 schema。
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
两个入口都不绑定 Pi、Claude Code、Codex、Cursor、OpenCode 或其他 Agent;Skill、MCP 和 Agent 插件只是上层 adapter,不进入核心。要求 Node.js 22.19+。
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## 能力
|
|
13
13
|
|
|
14
|
-
| 能力 | Provider
|
|
14
|
+
| 能力 | Provider 类型 | 规范化输出 |
|
|
15
15
|
| --- | --- | --- |
|
|
16
16
|
| `search` | Tavily、Exa、Bocha、元宝搜索、Brave、SearXNG、AnySearch、XCrawl、DeepSeek、xAI x_search、xAI web_search | `rank`、`title`、`url`、`snippet` |
|
|
17
17
|
| `extract` | Firecrawl v2、Jina Reader、Exa Contents、AnySearch、XCrawl、DeepSeek Fetch、HTTP | Markdown `Document` |
|
|
18
18
|
|
|
19
|
-
Provider
|
|
19
|
+
Provider 类型是具体实现,Provider 实例是该类型的一份配置,因此 `exa_team` 与 `exa_personal` 可以共存。每项能力都有主 `providers` 路由和 `providers_fallback` 路由,两者共同决定启用的实例和 `auto` 顺序。
|
|
20
20
|
|
|
21
21
|
## 安装
|
|
22
22
|
|
|
23
|
-
要求 Node.js 22.19 或更高版本。
|
|
24
|
-
|
|
25
|
-
从 npm 全局安装:
|
|
26
|
-
|
|
27
23
|
```sh
|
|
28
|
-
npm install --global web-access-cli
|
|
24
|
+
npm install --global web-access-cli # 或 pnpm add --global web-access-cli
|
|
29
25
|
web-access --help
|
|
30
26
|
```
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
源码方式:`pnpm install --frozen-lockfile && pnpm check`。网关在同一份源码中运行(`node --import tsx src/server.ts`),构建后为 `pnpm start:gateway`;生产部署用 GHCR 上的镜像,Compose 模板与密钥约定见 [deploy/README.md](deploy/README.md)。
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
pnpm add --global web-access-cli
|
|
36
|
-
web-access --help
|
|
37
|
-
```
|
|
30
|
+
目录:`src/cli.ts` 与 `src/server.ts` 是两个入口,`src/gateway/` 承载工具协议,`src/core/`、`src/providers/`、`src/transport/` 由两者共用。Adapter 只做协议映射,回退、超时、envelope 和退出码都在 `src/core`。
|
|
38
31
|
|
|
39
|
-
|
|
32
|
+
## CLI
|
|
40
33
|
|
|
41
34
|
```sh
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
pnpm pack:check
|
|
47
|
-
```
|
|
35
|
+
web-access search "TypeScript release" --provider exa --limit 10 --freshness month
|
|
36
|
+
web-access search "browser automation" --include-domain example.com --exclude-domain blocked.example.com
|
|
37
|
+
web-access extract https://example.com/article --provider http --timeout 30000
|
|
38
|
+
web-access extract https://example.com/article --json
|
|
48
39
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
src/server.ts DeepSeek 兼容网关的独立进程入口
|
|
54
|
-
src/config/ 配置文件、环境变量与 Route 合并
|
|
55
|
-
src/core/ 公共类型、schema、错误、路由和诊断
|
|
56
|
-
src/gateway/ 网关协议 schema、服务映射与 HTTP 边界
|
|
57
|
-
src/providers/ Provider adapter、registry、HTTP/RSC 提取
|
|
58
|
-
src/transport/ 代理、超时、重定向和响应大小限制
|
|
59
|
-
schemas/ 构建生成的 JSON Schema
|
|
60
|
-
test/ node:test 单元测试与本地 HTTP 集成测试
|
|
61
|
-
deploy/ 网关公开部署模板、配置示例与运维说明
|
|
40
|
+
web-access providers # 路由、能力、凭据与 URL 状态
|
|
41
|
+
web-access doctor # 仅本地配置检查,不联网
|
|
42
|
+
web-access config init # 按凭据环境变量生成配置
|
|
43
|
+
web-access config edit # 用 $VISUAL/$EDITOR 打开
|
|
62
44
|
```
|
|
63
45
|
|
|
64
|
-
|
|
46
|
+
通用选项:`--config <path>`、`--json`、`--help`、`--version`。能力命令输出面向人的 Markdown,`config init` 输出创建的文件路径,所有失败输出单个 JSON envelope。退出码:`0` 成功,`2` 输入/配置无效或 Provider 未启用,`1` 运行时或 doctor 失败,`130` 取消。
|
|
65
47
|
|
|
66
|
-
|
|
48
|
+
不提供 batch/all、answer、PDF 专线、Node SDK 或通用 MCP。另有一个可选的 [Agent Skill](skills/web-access-cli/SKILL.md),仅供源码仓库使用,不进入 npm 包。
|
|
67
49
|
|
|
68
|
-
|
|
69
|
-
pnpm install
|
|
70
|
-
pnpm lint
|
|
71
|
-
pnpm typecheck
|
|
72
|
-
pnpm test
|
|
73
|
-
pnpm build
|
|
74
|
-
pnpm pack:check
|
|
75
|
-
pnpm test:docker
|
|
76
|
-
```
|
|
50
|
+
## HTTP 网关
|
|
77
51
|
|
|
78
|
-
|
|
52
|
+
常驻进程,用 [DeepSeek Search 与 Fetch API](https://api-docs.deepseek.com/zh-cn/guides/search) 提供同一套 Provider、路由和传输:端点、鉴权头、请求字段和错误 envelope 均与官方一致,客户端只需改写 base URL,不改变 CLI 契约。
|
|
79
53
|
|
|
80
|
-
|
|
54
|
+
以 Docker 镜像方式运行:`ghcr.io/juexe/web-access-cli`,多架构 `linux/amd64` 与 `linux/arm64`,每次 GitHub Release 自动发布精确版本标签,正式版另加 `latest`。部署只需要 Docker,不需要 Node.js 或 pnpm:
|
|
81
55
|
|
|
82
56
|
```sh
|
|
83
|
-
web-access
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
web-access extract https://example.com/article
|
|
88
|
-
web-access extract https://example.com/article --provider http --timeout 30000
|
|
89
|
-
web-access extract https://example.com/article --json
|
|
57
|
+
docker pull ghcr.io/juexe/web-access-cli:0.7.0
|
|
58
|
+
docker compose -f deploy/compose.yaml --env-file personal/deploy.env up -d --wait gateway
|
|
59
|
+
```
|
|
90
60
|
|
|
91
|
-
|
|
92
|
-
web-access doctor
|
|
61
|
+
也可直接跑源码;默认监听 `127.0.0.1:8080`:
|
|
93
62
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
web-access
|
|
97
|
-
|
|
63
|
+
```sh
|
|
64
|
+
# 源码运行
|
|
65
|
+
WEB_ACCESS_CONFIG=~/.config/web-access-cli/config.json \
|
|
66
|
+
WEB_ACCESS_GATEWAY_API_KEY_FILE=/path/to/gateway-api-key \
|
|
67
|
+
node --import tsx src/server.ts
|
|
98
68
|
```
|
|
99
69
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
70
|
+
| 方法 | 路径 | 说明 |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| `POST` | `/v1/tools/search` | 兼容 DeepSeek Search |
|
|
73
|
+
| `POST` | `/v1/tools/fetch` | 兼容 DeepSeek Fetch |
|
|
74
|
+
| `GET` | `/healthz`、`/readyz` | 存活与配置就绪,无需鉴权 |
|
|
75
|
+
| `GET` | `/panel` | 管理后台页面骨架,无需鉴权也不含数据 |
|
|
76
|
+
| `GET`/`DELETE` | `/admin/api/records` | 请求记录,需要 Bearer Key |
|
|
77
|
+
| `GET` | `/admin/api/overview` | 运行统计、路由就绪情况与各实例计数 |
|
|
78
|
+
| `PUT` | `/admin/api/config` | 修改路由、预算与实例;热生效并写回文件 |
|
|
79
|
+
| `POST` | `/admin/api/config/reload` | 从磁盘重载配置文件 |
|
|
80
|
+
|
|
81
|
+
- Bearer Key 只从文件读取,按定长摘要比较,并拒绝重复 `Authorization`。网关是私有单用户部署,不额外设本地并发闸门、请求体大小上限和读取超时,也不会自行产生 413/408。响应带 `Cache-Control: no-store`。
|
|
82
|
+
- 搜索字段:`query`(1–128 字符)、`count`(1–50,默认 10)、`ori_question`(非空时 1–128 字符)、`localization`(非空时须为 IP)、`need_content`(布尔,默认 `false`)。Fetch 只接受一个不超过 8192 字符的绝对 HTTP(S) URL。未知字段被忽略,不能覆盖 Provider、凭据、超时或配置。
|
|
83
|
+
- 响应只保证协议兼容,不等同官方引擎:`summary` 复用 `snippet`,`rerank_score` 恒为 `0`,`authority` 恒为 `-1`,`site_name`/`site_icon`/`date` 为 `null`。按分数或权威度过滤的客户端必须改策略,结果数量、排序和质量都不作承诺。
|
|
84
|
+
- `ori_question` 与 `localization` 只做校验,核心无对应能力,不会传给 Provider。
|
|
85
|
+
- `need_content=true` 按排名补抓:并发 2、总窗口 30 秒、单项 10 秒、单次尝试 3 秒;失败时保留结果、内容留空。补抓与响应都不设大小上限,且**补抓会消耗提取配额**。Fetch 与补抓派生自己的配置,正文阈值降为 1 字符以放行短页面;源站 Markdown 探测仍需 500 字符。客户端断开会取消在途工作。
|
|
86
|
+
- 错误固定为 `{ "error": { "message", "type": "…", "param": null, "code" } }`:400 `invalid_request_error`、401 `invalid_api_key`、402 `insufficient_quota`、404 `no_usable_content` 或未知路径、405 方法不允许、503 正在停止、504 `upstream_timeout`,500 表示 Provider、凭据或配置失败。429 只表示上游限流。
|
|
87
|
+
- 工具请求从不改写 Provider 顺序,也不触发配置写回。唯一写入方是后台「配置管理」工作区与 `/admin/api/config*`:热生效并原子写回,配置文件只读挂载时退化为仅内存生效。
|
|
88
|
+
- 面板在内存中保留最近 500 条记录:状态、耗时、错误、Provider、query/URL、尝试链路、摘要与截断正文预览(搜索结果 2 000 字符、Fetch 4 000 字符),从不含完整正文、header 或凭据。`#apikey=<key>` 片段可直接登录,脚本读取后立即从地址栏移除并存入 `sessionStorage`。
|
|
89
|
+
|
|
90
|
+
### 在 DSH 中直接使用
|
|
91
|
+
|
|
92
|
+
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)自带 `@deepseek-ai/dsh-web-deepseek-api`,说的正是这套 API,因此把 `web_search` 与 `web_fetch` 指过来不需要额外插件,只要一个 base URL。`~/.dsh/cordis.patch.yml`:
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
- id: web
|
|
96
|
+
name: "@deepseek-ai/dsh-web"
|
|
97
|
+
config:
|
|
98
|
+
searchProvider: deepseek-search-api
|
|
99
|
+
fetchProvider: deepseek-fetch-api
|
|
100
|
+
- id: web-deepseek-api
|
|
101
|
+
name: "@deepseek-ai/dsh-web-deepseek-api"
|
|
102
|
+
config:
|
|
103
|
+
apiKeyEnv: DEEPSEEK_API_KEY # 这里要放网关 Key,不是 DeepSeek Key
|
|
104
|
+
baseURL: http://127.0.0.1:8080/v1/tools
|
|
105
|
+
```
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
- `--json`:输出紧凑 schema v2 JSON envelope;不指定时,成功命令输出面向人的 Markdown,失败始终输出 JSON。
|
|
106
|
-
- `--help`、`--version`:输出常规 CLI 帮助或版本文本。
|
|
107
|
+
`baseURL` 写完整 API 基址,含路径前缀但不含 `/search` 或 `/fetch`;插件的 `apiKeyEnv` 默认取 `DEEPSEEK_API_KEY`,需让它指向存网关 Key 的变量。此后 `web_search` 与 `web_fetch` 走本网关,除上文提到的占位分数字段外无需其他改动。网关是私有部署,应放在可信网络内而不是直接暴露公网。
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
部署、密钥、升级与回滚见 [deploy/README.md](deploy/README.md);架构决策见 [ADR 0019](docs/adr/0019-deepseek-tool-gateway.md)。
|
|
109
110
|
|
|
110
111
|
## 配置
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
所有平台的默认路径均为 `~/.config/web-access-cli/config.json`,其中 `~` 表示当前用户的主目录。环境变量 `WEB_ACCESS_CONFIG` 可以指定其他路径;命令行 `--config` 优先级更高。
|
|
115
|
-
|
|
116
|
-
`web-access config edit` 会在配置文件缺失时创建父目录和完整默认配置,再优先使用 `VISUAL`、其次使用 `EDITOR` 打开;变量值可以包含带引号的可执行文件路径和参数,解析时不会执行 shell,并将配置路径作为独立的最后一个参数传入。已有文件会原样打开,即使内容暂时不是有效 JSON 也不会被覆盖或格式化。命令只等待编辑器进程启动,不等待编辑器关闭。两个变量都未设置、格式无效或启动失败时返回 `open_failed`;如果配置刚刚创建成功,文件仍会保留以便手动编辑。
|
|
113
|
+
严格 JSON,未知字段报错。解析顺序为 `--config`、`WEB_ACCESS_CONFIG`、`~/.config/web-access-cli/config.json`;默认路径缺失时使用内置默认值,显式路径缺失时返回 `config_error`,不扫描父目录。
|
|
117
114
|
|
|
118
|
-
`config
|
|
119
|
-
|
|
120
|
-
完整 JSON Schema 位于 [schemas/config.schema.json](schemas/config.schema.json)。示例:
|
|
115
|
+
`config edit` 在文件缺失时创建完整默认配置并用 `VISUAL`(其次 `EDITOR`)打开,不经 shell 解释、不重排内容;`config init` 按标准凭据环境变量生成配置且不覆盖已有文件。环境变量优先于明文 key。完整 schema 见 [schemas/config.schema.json](schemas/config.schema.json):
|
|
121
116
|
|
|
122
117
|
```json
|
|
123
118
|
{
|
|
124
|
-
"$schema": "https://unpkg.com/web-access-cli@0.
|
|
119
|
+
"$schema": "https://unpkg.com/web-access-cli@0.7.0/schemas/config.schema.json",
|
|
125
120
|
"providers": [
|
|
126
|
-
{
|
|
127
|
-
|
|
128
|
-
"type": "exa",
|
|
129
|
-
"apiKeyEnv": "TEAM_EXA_API_KEY",
|
|
130
|
-
"headers": {
|
|
131
|
-
"X-Team": "docs"
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
"id": "searx_local",
|
|
136
|
-
"type": "searxng",
|
|
137
|
-
"baseUrl": "http://127.0.0.1:8080"
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
"id": "firecrawl_local",
|
|
141
|
-
"type": "firecrawl",
|
|
142
|
-
"baseUrl": "http://127.0.0.1:3002"
|
|
143
|
-
}
|
|
121
|
+
{ "id": "exa_team", "type": "exa", "apiKeyEnv": "TEAM_EXA_API_KEY" },
|
|
122
|
+
{ "id": "firecrawl_local", "type": "firecrawl", "baseUrl": "http://127.0.0.1:3002" }
|
|
144
123
|
],
|
|
145
|
-
"search": {
|
|
146
|
-
|
|
147
|
-
"providers_fallback": ["deepseek"],
|
|
148
|
-
"limit": 5,
|
|
149
|
-
"timeoutMs": 120000,
|
|
150
|
-
"attemptTimeoutMs": 60000,
|
|
151
|
-
"maxResponseBytes": 5242880
|
|
152
|
-
},
|
|
153
|
-
"extract": {
|
|
154
|
-
"providers": ["firecrawl_local", "jina", "exa_team"],
|
|
155
|
-
"providers_fallback": ["http"],
|
|
156
|
-
"timeoutMs": 120000,
|
|
157
|
-
"attemptTimeoutMs": 45000,
|
|
158
|
-
"maxResponseBytes": 5242880,
|
|
159
|
-
"minContentCharacters": 500
|
|
160
|
-
}
|
|
124
|
+
"search": { "providers": ["exa_team"], "providers_fallback": ["brave"] },
|
|
125
|
+
"extract": { "providers": ["firecrawl_local"], "providers_fallback": ["http"] }
|
|
161
126
|
}
|
|
162
127
|
```
|
|
163
128
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
默认 Route:
|
|
167
|
-
|
|
168
|
-
- Search 主轮:`tavily -> exa -> bocha -> yuanbao -> brave -> searxng -> anysearch -> xcrawl -> deepseek`
|
|
169
|
-
- Search fallback:`xai_x_search -> xai_web_search`
|
|
170
|
-
- Extract 主轮:`firecrawl -> jina -> exa -> anysearch -> xcrawl -> deepseek`
|
|
171
|
-
- Extract fallback:`http`
|
|
172
|
-
|
|
173
|
-
默认 Route 将内置 provider 分为主轮和 fallback。自定义 ID 会合并到 Instance 列表,但仍需显式加入 Route;省略能力 Route 时使用上述默认分组,Search 主 Route 显式空数组会报错,Extract 主 Route 可以显式为空以禁用 Extract。`auto` 会跳过未完成配置的 Instance。AnySearch 与 XCrawl 可设置 `searchFilterMode`:`strict`(默认,遇到 freshness 时跳过)或 `best_effort`(将日期改写为查询片段)。域名条件会改写查询并在本地再次严格过滤。XCrawl Extract 固定使用同步 Scrape 的 Markdown 输出;Map、Crawl 和异步任务不属于当前 CLI 能力。
|
|
174
|
-
|
|
175
|
-
元宝搜索调用腾讯云 `POST /SearchPro`,使用 Bearer 服务 API KEY 和小写驼峰请求体(`Query`,可选 `Site` 与 `Freshness`)。单个 `site:` 指定域名改写为 `Site=<domain>`,不超过五个排除域名改写为 `Site=exclude:<domain>|<domain>`,其余组合只在本地过滤。`Pages` 的每一项都是 JSON 字符串,映射为 `title`/`url`/`snippet`,摘要优先取标准摘要 `passage`,其次才是动态摘要 `content`。HTTP 200 中返回的 `UnauthorizedOperation`、`ResourceNotFound` 等业务错误保持可回退,`auto` 会继续尝试下一个 Provider。该 Provider 仅支持 Search;`--limit` 不超过 10 时不发送 `Cnt`,以免极速版拒绝请求,超出时按 10 向上取整发送(上限 50)。
|
|
129
|
+
内置实例:`tavily`、`exa`、`bocha`、`yuanbao`、`brave`、`searxng`、`anysearch`、`xcrawl`、`deepseek`、`firecrawl`、`jina`、`http`、`xai_x_search`、`xai_web_search`。复用内置 ID 表示覆盖该实例,新 ID 表示新增同类型实例;只有写入路由的实例才会启用。默认路由:
|
|
176
130
|
|
|
177
|
-
|
|
131
|
+
- Search:`tavily -> exa -> bocha -> yuanbao -> brave -> searxng -> anysearch -> xcrawl -> deepseek`,回退 `xai_x_search -> xai_web_search`
|
|
132
|
+
- Extract:`firecrawl -> jina -> exa -> anysearch -> xcrawl -> deepseek`,回退 `http`
|
|
178
133
|
|
|
179
|
-
|
|
134
|
+
Search 主路由显式置空非法;Extract 可用空主路由关闭。AnySearch 与 XCrawl 支持 `searchFilterMode`:`strict`(遇 freshness 跳过)或 `best_effort`(把 freshness 改写成查询片段)。元宝向 `/SearchPro` 发送 `Query`/`Site`/`Freshness`,响应体内的错误仍可回退。DeepSeek 走 `/v1/tools/search` 与 `/v1/tools/fetch`,把 freshness 和域名改写为 `after:`/`site:` 提示并在本地再次过滤。xAI 每次调用读取 `XAI_AUTH_JSON` 中的 OAuth JSON 且不刷新,作主 Provider 时需调高 `attemptTimeoutMs`。
|
|
180
135
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
环境变量优先于 JSON 中的明文 key。内置 Instance 支持这些标准变量:
|
|
184
|
-
|
|
185
|
-
| Type | API key | Base URL |
|
|
136
|
+
| 类型 | API key | Base URL |
|
|
186
137
|
| --- | --- | --- |
|
|
187
|
-
| Tavily | `
|
|
188
|
-
| Exa | `EXA_API_KEY` | `EXA_BASE_URL` |
|
|
138
|
+
| Tavily / Exa / Brave / Firecrawl / XCrawl | `<NAME>_API_KEY` | `<NAME>_BASE_URL` |
|
|
189
139
|
| Bocha | `BOCHA_API_KEY` | `BOCHA_BASE_URL`,默认 `https://api.bocha.cn` |
|
|
190
|
-
|
|
|
191
|
-
|
|
|
192
|
-
|
|
|
193
|
-
|
|
|
194
|
-
| HTTP | 无 | 无 |
|
|
195
|
-
| AnySearch | `ANYSEARCH_API_KEY`,可选 | `ANYSEARCH_BASE_URL`,默认 `https://api.anysearch.com` |
|
|
196
|
-
| XCrawl | `XCRAWL_API_KEY` | `XCRAWL_BASE_URL`,默认 `https://run.xcrawl.com` |
|
|
197
|
-
| DeepSeek | `DEEPSEEK_API_KEY` | 无标准环境变量;默认 `https://api.deepseek.com` |
|
|
198
|
-
| xAI Search | `XAI_AUTH_JSON` | 无标准环境变量;默认 `https://cli-chat-proxy.grok.com/v1`,模型 `grok-4.6` |
|
|
199
|
-
|
|
200
|
-
自定义 Instance 使用 `apiKeyEnv` 和 `baseUrlEnv` 指定自己的环境变量。所有远端 Provider 都可以设置 `baseUrl` 和附加 `headers`。公共 `api.firecrawl.dev` 需要 key;自托管 Firecrawl v2 可以不设置 key。
|
|
201
|
-
|
|
202
|
-
## 执行与回退
|
|
140
|
+
| SearXNG | 无 | `SEARXNG_BASE_URL`,必填 |
|
|
141
|
+
| Jina / AnySearch | `JINA_API_KEY` / `ANYSEARCH_API_KEY`,可选 | `<NAME>_BASE_URL` |
|
|
142
|
+
| DeepSeek | `DEEPSEEK_API_KEY` | 固定 `https://api.deepseek.com` |
|
|
143
|
+
| xAI Search | `XAI_AUTH_JSON`(OAuth 文件) | 默认 `https://cli-chat-proxy.grok.com/v1`,`grok-4.6` |
|
|
203
144
|
|
|
204
|
-
|
|
145
|
+
自定义实例用 `apiKeyEnv`/`baseUrlEnv` 指定变量名,可设置 `baseUrl` 与 `headers`。公共 Firecrawl Cloud 需要 key,自托管 Firecrawl v2 不需要。
|
|
205
146
|
|
|
206
|
-
|
|
207
|
-
2. Provider 返回的最终 HTTP 响应不在 2xx 范围时,包括鉴权、请求、限流和服务器错误,Router 会尝试下一个实例。
|
|
208
|
-
3. 网络错误、超时、响应过大、无可用正文等其他可恢复错误也会继续 Route。
|
|
209
|
-
4. 没有最终非 2xx 响应的不可恢复错误,例如无效输入或在成功响应中检测到不支持的内容,会立即停止。
|
|
210
|
-
5. 两组实例全部失败时返回 `provider_exhausted`。提取过程中产生的最佳短正文会保留在 `partial`。
|
|
147
|
+
## 路由与限制
|
|
211
148
|
|
|
212
|
-
|
|
149
|
+
两个入口共用同一 Router,差异只在输出形态、单次命令选项,以及网关固定的 Fetch/补抓阈值。
|
|
213
150
|
|
|
214
|
-
|
|
151
|
+
`auto` 先走主路由,主组出现可回退失败后才进入回退路由。未完成配置的实例记录为失败并跳过;Provider 非 2xx 响应和可恢复错误(网络、超时、响应过大、无可用正文)继续下一个实例;无效输入和不支持内容立即停止;全部失败返回 `provider_exhausted`,最佳短正文保留在 `partial`。显式 `--provider` 只执行一次且不回退,不在路由中时返回 `provider_disabled`。`retryable` 描述同一 Provider 能否重试,不是切换条件。
|
|
215
152
|
|
|
216
|
-
|
|
153
|
+
`extract --provider auto` 在启用 HTTP 时先探测一个 Markdown 变体:文件型路径用 `.md`,目录用 `index.md`,只接受足够长的非 HTML 文本。未命中透明回退,命中记在 HTTP 实例名下且不改变顺序。
|
|
217
154
|
|
|
218
|
-
|
|
155
|
+
CLI 每次 `auto` 后,成功实例移到所在组队头,可回退失败的移到队尾,不跨组移动。Search 与 Extract 独立学习;显式实例、不可回退失败和取消都不改变顺序,写入原子且后者覆盖前者。网关从不改写路由。
|
|
219
156
|
|
|
220
|
-
|
|
157
|
+
默认限制:Search 总 120 秒、单次 60 秒;Extract 总 120 秒、单次 45 秒;单响应 5 MiB。`--timeout` 只覆盖本次总超时。
|
|
221
158
|
|
|
222
|
-
##
|
|
159
|
+
## 输出
|
|
223
160
|
|
|
224
|
-
|
|
161
|
+
能力命令输出 schema version 2。`--json` 时包含 `schemaVersion`、`ok`、最终实例和 `data`;失败附加紧凑 `error`、`attempts`(实例、错误码、可选状态码),可能有 `partial`。顺序写回失败时追加 `warnings`,不替换结果。面向人的输出为 Markdown:`provider` front matter 加编号结果列表或提取正文;诊断命令输出标题加 JSON。脚本应显式传 `--json`。
|
|
225
162
|
|
|
226
163
|
```json
|
|
227
|
-
{
|
|
228
|
-
"
|
|
229
|
-
"ok": true,
|
|
230
|
-
"provider": "exa",
|
|
231
|
-
"data": {
|
|
232
|
-
"results": [
|
|
233
|
-
{
|
|
234
|
-
"rank": 1,
|
|
235
|
-
"title": "Example",
|
|
236
|
-
"url": "https://example.com/",
|
|
237
|
-
"snippet": "Example snippet"
|
|
238
|
-
}
|
|
239
|
-
]
|
|
240
|
-
}
|
|
241
|
-
}
|
|
164
|
+
{ "schemaVersion": 2, "ok": true, "provider": "exa",
|
|
165
|
+
"data": { "results": [{ "rank": 1, "title": "Example", "url": "https://example.com/", "snippet": "..." }] } }
|
|
242
166
|
```
|
|
243
167
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
面向人的输出中,提取以 YAML front matter 开头、随后是 Provider 规范化的 Markdown 正文;搜索使用编号 Markdown 列表;诊断和配置编辑使用标题加格式化 JSON 数据。元数据值统一使用 JSON 双引号标量编码,正文内容不改写。已有脚本和其他机器消费者应显式追加 `--json`。
|
|
247
|
-
|
|
248
|
-
默认提取输出示例:
|
|
249
|
-
|
|
250
|
-
```markdown
|
|
251
|
-
---
|
|
252
|
-
provider: "local_http"
|
|
253
|
-
url: "https://example.com/article"
|
|
254
|
-
title: "Example title"
|
|
255
|
-
---
|
|
256
|
-
|
|
257
|
-
# Article content
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
所有成功和失败 envelope 使用 schema version 2。稳定 schema 位于 [schemas](schemas)。
|
|
261
|
-
|
|
262
|
-
退出码:
|
|
263
|
-
|
|
264
|
-
- `0`:成功
|
|
265
|
-
- `2`:输入、配置、未知或未启用 provider
|
|
266
|
-
- `1`:运行时/provider/doctor/编辑器启动失败
|
|
267
|
-
- `130`:用户取消
|
|
268
|
-
|
|
269
|
-
`providers` 会列出每个 Instance 的 Type、能力、Route 启用状态、凭据来源和 base URL 来源;`searchRoute`/`searchFallbackRoute` 与 `extractRoute`/`extractFallbackRoute` 是下一次 `auto` 使用的两组有效顺序。`doctor` 只做本地配置检查,不主动调用远端 API;当已启用 Route 中存在未配置 Instance 时,命令返回 `doctor_failed` 和退出码 `1`。
|
|
270
|
-
|
|
271
|
-
## DeepSeek 兼容 HTTP 网关
|
|
272
|
-
|
|
273
|
-
仓库另外提供一个**独立**的 HTTP 服务,把同样的 provider、路由和传输实现包装成 DeepSeek 工具协议。它不是 CLI 的替代品:CLI 的命令、退出码、schema v2 envelope 和 npm bin 契约都不变。
|
|
274
|
-
|
|
275
|
-
```sh
|
|
276
|
-
# 源码运行(默认监听 127.0.0.1:8080)
|
|
277
|
-
WEB_ACCESS_CONFIG=~/.config/web-access-cli/config.json \
|
|
278
|
-
WEB_ACCESS_GATEWAY_API_KEY_FILE=/path/to/gateway-api-key \
|
|
279
|
-
pnpm start:gateway # 或 node --import tsx src/server.ts
|
|
280
|
-
|
|
281
|
-
# 构建后运行
|
|
282
|
-
node dist/server.js
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
| 方法 | 路径 | 说明 |
|
|
286
|
-
| --- | --- | --- |
|
|
287
|
-
| `POST` | `/v1/tools/search` | DeepSeek Search 兼容 |
|
|
288
|
-
| `POST` | `/v1/tools/fetch` | DeepSeek Fetch 兼容 |
|
|
289
|
-
| `GET` | `/`、`/panel` | 请求记录面板(HTML,页面本身不含数据) |
|
|
290
|
-
| `GET` | `/admin/api/records` | 最近请求记录(需要 Bearer Key) |
|
|
291
|
-
| `GET` | `/healthz` | 进程存活,无需鉴权 |
|
|
292
|
-
| `GET` | `/readyz` | 配置/生命周期就绪,无需鉴权 |
|
|
293
|
-
|
|
294
|
-
网关只从文件读取独立的 Bearer Key(`WEB_ACCESS_GATEWAY_API_KEY_FILE`),使用 Node crypto 做定长摘要比较,并拒绝重复 `Authorization`。入站请求体按流计数,上限 64 KiB,读取超时 10 秒;全服务最多 4 个在途工具请求,满额返回 429。成功与错误都使用 `Cache-Control: no-store`。
|
|
295
|
-
|
|
296
|
-
请求字段与官方一致:
|
|
297
|
-
|
|
298
|
-
| 字段 | 行为 |
|
|
299
|
-
| --- | --- |
|
|
300
|
-
| `query` | 必填,1–128 个 Unicode 字符,不能全为空白;原样保留搜索语法 |
|
|
301
|
-
| `count` | 1–50 的整数,缺省 10 |
|
|
302
|
-
| `ori_question` | 可省略或 `null`;非 null 时 1–128 个字符 |
|
|
303
|
-
| `localization` | 可省略,默认空字符串;非空必须是 IP 地址 |
|
|
304
|
-
| `need_content` | 可省略,默认 `false`;必须是布尔值 |
|
|
305
|
-
|
|
306
|
-
Fetch 只接受非空、最长 8192 字符、含 hostname、无 userinfo 的绝对 HTTP(S) URL。未知请求字段会被忽略,且无法通过未知字段指定 provider、凭据、timeout 或配置。
|
|
307
|
-
|
|
308
|
-
**响应是协议兼容而非与官方搜索引擎等价**:`summary` 直接复制 `snippet`,`rerank_score` 恒为 `0`,`authority` 恒为 `-1`,`site_name`/`site_icon`/`date` 恒为 `null`。占位评分**不是** DeepSeek 的质量评分;依赖 `rerank_score >= 1.5` 或 `authority >= 3` 筛选的客户端必须调整策略,否则会过滤掉全部结果。网关不承诺结果数量、排序或摘要质量与官方一致,也不跨 provider 凑数或重新分页。
|
|
309
|
-
|
|
310
|
-
`ori_question` 与 `localization` 本期接受并校验,但中立核心没有对应能力,因此不影响 provider 请求,也不会拼进 `query`。
|
|
311
|
-
|
|
312
|
-
`need_content=true` 时为每条结果补抓正文:按排名顺序、最多两路并发、总预算 30 秒、单篇 10 秒、每次 provider 尝试 3 秒。失败、超时或超限的正文留空但结果保留;单篇正文最多 256 KiB(JSON 编码后),完整响应最多 8 MiB,超限时从低排名起清空 `content`。**补抓会消耗 extract 上游额度。**
|
|
313
|
-
|
|
314
|
-
网关为 Fetch 与补抓派生自己的配置,正文最短阈值降为 1 个字符,因此有效短页面会成功;源站 `.md` 猜测仍要求至少 500 字符(或原配置阈值取大者),避免短小的 `Not found` 页面误命中。搜索和 Fetch 各用现有配置的总超时,补抓有独立的 30 秒窗口;客户端断开会取消在途工作。
|
|
315
|
-
|
|
316
|
-
错误统一为 `{ "error": { "message": "...", "type": "...", "param": null, "code": "..." } }`:400 输入错误、401 `invalid_api_key`、402 额度不足、404 无可用正文或直连目标不可用、408 读取请求体超时、413 请求体过大、429 限流(带 `Retry-After`)、504 下游超时、500 凭据/配置/未知失败/输出超限。目标站点的 401/403 属于 Fetch 不可用;云 provider 的 401/403 返回 500。
|
|
317
|
-
|
|
318
|
-
网关不写回 provider 顺序,也不修改配置:服务运行期间使用启动时加载的配置快照。部署方式、Docker Compose 模板、secret 挂载、诊断、升级与回滚见 [deploy/README.md](deploy/README.md);架构决策见 [docs/adr/0019-deepseek-tool-gateway.md](docs/adr/0019-deepseek-tool-gateway.md)。
|
|
319
|
-
|
|
320
|
-
浏览器打开网关根路径或 `/panel`,输入网关 Key 即可查看最近 500 条工具请求(状态、耗时、错误码、provider、query/URL 与前 5 条结果标题)。记录只保存在内存中,重启清空,不记录响应正文、header 或凭据;未鉴权请求不进入记录。面板 HTML 本身不含数据,`/admin/api/records` 复用同一个 Bearer Key。也可用 `#apikey=<key>` 片段直接打开,脚本读取后立即从地址栏移除;不要用查询串传递 Key。
|
|
321
|
-
|
|
322
|
-
## HTTP 与安全边界
|
|
323
|
-
|
|
324
|
-
- 默认遵循 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY`、`NO_PROXY`。
|
|
325
|
-
- 最多跟随 5 次重定向;跨 origin 重定向会移除鉴权、Cookie 和常见 token headers。
|
|
326
|
-
- 所有响应都执行流式字节上限,避免先完整缓冲超大响应。
|
|
327
|
-
- HTTP Extract 使用 LinkeDOM、Mozilla Readability、Turndown,并对 Next.js RSC payload 做后备解析。
|
|
328
|
-
- HTTP Extract 在 route 已启用 HTTP Instance 时优先读取可用的源站 Markdown 变体(`.md` 或目录 `index.md`)。
|
|
329
|
-
- PDF、图片、音频、视频、zip 和通用二进制内容会返回 `unsupported_content`。
|
|
330
|
-
- 按项目设计,CLI 不阻止 localhost、私网地址或云元数据 URL。调用者必须在不可信输入场景中自行实施 URL allowlist、网络隔离或出站代理策略。
|
|
168
|
+
`providers` 报告每个实例的类型、能力、路由状态、凭据与 URL 来源,以及下次调用的有效顺序;启用路由中存在未配置实例时 `doctor` 返回 `1`。
|
|
331
169
|
|
|
332
|
-
##
|
|
170
|
+
## 安全边界
|
|
333
171
|
|
|
334
|
-
|
|
172
|
+
- 默认遵循 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY`、`NO_PROXY`;最多跟随五次重定向,跨 origin 时移除鉴权、Cookie 和 token 类 header。
|
|
173
|
+
- 响应按流限制 5 MiB,不先无界缓冲。HTTP 提取使用 LinkeDOM、Readability、Turndown,并带 RSC 后备;二进制与媒体返回 `unsupported_content`。
|
|
174
|
+
- 按设计两个入口都不阻止 localhost、私网地址或云元数据 URL。不可信场景需自行加 allowlist、网络隔离或出站策略;网关定位为 Bearer Key 之后的私有单用户部署。
|
|
335
175
|
|
|
336
|
-
|
|
176
|
+
## 范围
|
|
337
177
|
|
|
338
|
-
|
|
178
|
+
Provider 与提取实现大量取自 `pi-web-access`,不含 Pi 专用注册、工具协议和 UI。参见 [CONTRIBUTING.md](CONTRIBUTING.md) 与 [SECURITY.md](SECURITY.md),MIT 许可,第三方声明见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
|