dsh-web-search-enhanced 0.0.1 → 0.0.2
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/CHANGELOG.md +18 -0
- package/LICENSE +16 -4
- package/README.md +218 -54
- package/docs/design.zh-CN.md +1 -1
- package/docs/harness-contract.md +1 -1
- package/lib/index.js +31 -10
- package/lib/types/index.d.ts +1 -1
- package/package.json +3 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `dsh-web-search-enhanced` package will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.0.2] - 2026-08-30
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- **Upstream 0.1.2-alpha.2 Settings API Alignment**: Migrated settings registration from deprecated top-level `installSettingsSection` and branded `settingsNamespace` to Cordis service-based `ctx.settings.installSection()` with native kebab-case string namespace, maintaining backwards compatibility with earlier versions.
|
|
9
|
+
- **Search Endpoint Failure Guidance**: Added standardized endpoint reporting and configuration recovery instructions to post-dispatch `WebError` failures (network errors, HTTP errors, response parsing errors) to align with upstream search provider behavioral specifications.
|
|
10
|
+
- **Verification Tooling**: Hardened `scripts/verify-package.mjs` with sandbox-safe cache directories and multi-pack fallback support.
|
|
11
|
+
|
|
12
|
+
## [0.0.1] - 2026-08-28
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- Initial release of `dsh-web-search-enhanced`.
|
|
16
|
+
- Support for Anthropic Messages, OpenAI Responses, and OpenAI Chat Completions search protocols.
|
|
17
|
+
- Follow mode (`current-session`) and fixed search configuration mode.
|
|
18
|
+
- DeepSeek Harness Web GUI settings card integration.
|
package/LICENSE
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026
|
|
3
|
+
Copyright (c) 2026 Yurzi
|
|
4
4
|
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
6
11
|
|
|
7
|
-
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
8
14
|
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,77 +1,241 @@
|
|
|
1
1
|
# dsh-web-search-enhanced
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/dsh-web-search-enhanced)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
**dsh-web-search-enhanced** 是为 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) 量身打造的增强型多协议联网搜索插件。
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- 跟随模式无法解析当前路由时,使用可配置的 <code>fallbackModel</code>;
|
|
9
|
-
- 通过 <code>protocol</code> 切换固定/兜底路由的三种非流式 HTTP 协议;
|
|
10
|
-
- 通过 <code>toolIdentifier</code> 覆盖上游内置搜索标识符;
|
|
11
|
-
- 通过 <code>maxTokens</code> 配置 <code>max_tokens</code> 或 <code>max_output_tokens</code>;
|
|
12
|
-
- 将三种响应中的来源与引用归一化为 DSH <code>WebSearchResult</code>;
|
|
13
|
-
- 在「设置 → 插件 → 插件配置」中提供可暂存、校验、保存、放弃和恢复 Profile 默认值的双语配置卡片;
|
|
14
|
-
- 拒绝携带凭据的 HTTP 重定向,并把取消、缺少凭据和上游错误映射为可路由的 <code>WebError</code> code。
|
|
9
|
+
### 🌟 核心价值:直接使用模型供应商自身提供的联网搜索
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
传统智能体方案通常需要额外购买和配置第三方搜索引擎 API(如 Tavily、Bing Search API、Google CSE 等),不仅流程繁琐,还带来了额外的账单与调用延迟。
|
|
17
12
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
**dsh-web-search-enhanced** 让你可以**直接调用模型供应商(如 DeepSeek、Anthropic Claude、OpenAI 等)自身原生集成的服务端联网搜索功能**:
|
|
14
|
+
- 🚫 **告别额外依赖**:无需申请或维护独立的搜索引擎 API Key,直接复用你现有的大模型 API 凭据。
|
|
15
|
+
- 💰 **极致降低成本**:依托各大模型供应商原生提供的高性价比或免费搜索能力,大幅节约外部检索成本。
|
|
16
|
+
- 🎯 **深度原生优化**:充分利用厂商针对大模型特别调优的网页抓取、实时索引、正文解析与引用标注体系,检索质量更高、响应更迅速。
|
|
17
|
+
- 🔄 **保持原生体验**:模型端保持原生 `web_search` 工具签名与交互体验不变,无缝支持 Anthropic Messages、OpenAI Responses API 及 OpenAI Chat Completions 三大主流上游协议,并提供 Web 可视化配置面板。
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
---
|
|
23
20
|
|
|
24
|
-
##
|
|
21
|
+
## ✨ 核心特性
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
- ⚡ **直接利用模型厂商内置搜索**:原生调用各大模型供应商自身的服务端搜索(如 Anthropic `web_search_20250305`、OpenAI `web_search` / `web_search_options`、DeepSeek 服务端搜索等),免去一切第三方搜索引擎开销。
|
|
24
|
+
- 🌐 **多协议全面兼容**:无缝支持 **Anthropic Messages v1** (`/messages`)、**OpenAI Responses API** (`/responses`) 与 **OpenAI Chat Completions API** (`/chat/completions`) 三大协议,兼容各类官方端点与第三方 / 自建 AI 网关。
|
|
25
|
+
- 🔄 **灵活的双路由模式**:
|
|
26
|
+
- **跟随当前会话 (`current-session`)**:自动继承当前会话正在使用的模型、提供方、调用协议与凭据,直接使用主模型供应商的搜索功能。
|
|
27
|
+
- **固定搜索路由 (`configured`)**:为联网搜索单独指定专用搜索模型(如 `deepseek-v4-flash`、`claude-3-7-sonnet`、`gpt-4o` 等),主对话与搜索模型分工明确。
|
|
28
|
+
- **智能平滑兜底 (`fallbackModel`)**:当跟随模式遇到未知或未配置的模型路由时,自动降级至备用模型,确保搜索永不断流。
|
|
29
|
+
- 🖥️ **Web 控制台可视化配置**:深度集成 DSH Web 端「设置 → 插件 → Web Search Enhanced」,支持中英文双语、即时表单校验、草稿暂存、一键保存与重置。
|
|
30
|
+
- 🔒 **凭据安全与隐私保护**:通过 DSH 原生 Credentials 机制安全写入并保管 API Key,公开设置文档绝不保存明文密钥;请求强制阻断携带凭据的恶意 HTTP 重定向。
|
|
31
|
+
- 🎯 **开箱即用无感集成**:上游响应中的来源和引用会自动归一化为标准的 DSH `WebSearchResult`;主模型提示词和工作流无需任何改动。
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
- id: web-search-enhanced
|
|
30
|
-
config:
|
|
31
|
-
modelMode: configured
|
|
32
|
-
protocol: anthropic-messages
|
|
33
|
-
baseURL: https://api.deepseek.com/anthropic/v1
|
|
34
|
-
model: deepseek-v4-flash
|
|
35
|
-
fallbackModel: deepseek-v4-flash
|
|
36
|
-
apiKeyEnv: WEB_SEARCH_ENHANCED_API
|
|
37
|
-
maxTokens: 4096
|
|
38
|
-
~~~
|
|
33
|
+
---
|
|
39
34
|
|
|
40
|
-
|
|
41
|
-
| --- | --- | --- |
|
|
42
|
-
| <code>modelMode</code> | <code>configured</code> | <code>configured</code> 使用固定路由;<code>current-session</code> 跟随当前模型、Provider 和调用协议 |
|
|
43
|
-
| <code>fallbackModel</code> | 固定 <code>model</code> | 当前 Session 路由无法解析时使用的模型 |
|
|
44
|
-
| <code>protocol</code> | <code>anthropic-messages</code> | 固定/兜底路由使用的协议 |
|
|
45
|
-
| <code>toolIdentifier</code> | 按协议推导 | Anthropic/Responses 的 tool type;Chat 的 vendor-options 模式为自定义选项字段名 |
|
|
46
|
-
| <code>maxTokens</code> | <code>4096</code> | Anthropic/Chat 写入 <code>max_tokens</code>,Responses 写入 <code>max_output_tokens</code> |
|
|
47
|
-
| <code>baseURL</code> | DeepSeek Anthropic base | 按协议追加 <code>/messages</code>、<code>/responses</code> 或 <code>/chat/completions</code> |
|
|
48
|
-
| <code>model</code> | <code>deepseek-v4-flash</code> | 支持服务端网页搜索的模型 ID |
|
|
49
|
-
| <code>apiKeyEnv</code> | <code>WEB_SEARCH_ENHANCED_API</code> | 固定/兜底路由读取 API Key 的凭据引用;当前会话模式优先使用当前 LLM 路由引用 |
|
|
50
|
-
| <code>maxUses</code> | <code>5</code> | 仅 Anthropic Messages 的 <code>max_uses</code> |
|
|
51
|
-
| <code>chatSearchMode</code> | <code>search-model</code> | 官方专用搜索模型,或明确声明的 <code>vendor-options</code> 扩展 |
|
|
52
|
-
| <code>searchContextSize</code> | 上游默认 | OpenAI 兼容模式可选 <code>low</code>、<code>medium</code>、<code>high</code> |
|
|
35
|
+
## 📦 快速安装
|
|
53
36
|
|
|
54
|
-
|
|
37
|
+
插件已正式发布至 npmjs,使用 DSH CLI 即可一键安装到 `web` Profile:
|
|
55
38
|
|
|
56
|
-
|
|
39
|
+
```bash
|
|
40
|
+
# 安装插件至 web profile
|
|
41
|
+
dsh plugin --profile web add dsh-web-search-enhanced
|
|
42
|
+
```
|
|
57
43
|
|
|
58
|
-
|
|
44
|
+
安装完成后,重启 `dsh web` 服务即可生效:
|
|
59
45
|
|
|
60
|
-
|
|
46
|
+
```bash
|
|
47
|
+
# 启动或重启 DSH Web 服务
|
|
48
|
+
dsh web
|
|
49
|
+
```
|
|
61
50
|
|
|
62
|
-
|
|
51
|
+
> 💡 **提示**:安装后,插件随附的 `cordis.patch.yml` 会自动将搜索提供方指向 `enhanced-search`,并禁用原生默认搜索提供方。
|
|
63
52
|
|
|
64
|
-
|
|
53
|
+
---
|
|
65
54
|
|
|
66
|
-
|
|
55
|
+
## 🚀 快速上手与配置
|
|
56
|
+
|
|
57
|
+
### 方式一:Web 界面可视化配置(推荐)
|
|
58
|
+
|
|
59
|
+
1. 打开 DeepSeek Harness Web 界面(默认 `http://127.0.0.1:3080`)。
|
|
60
|
+
2. 点击左侧/顶部导航栏的 **设置 (Settings)** → **插件 (Plugins)**。
|
|
61
|
+
3. 找到 **Web Search Enhanced (插件配置)** 卡片。
|
|
62
|
+
4. 根据需要选择**模型路由**、**API 协议**、**接口地址 (Base URL)** 与 **模型标识 (Model ID)**。
|
|
63
|
+
5. 在 **API Key** 输入框中输入对应的模型供应商 API 密钥(输入后仅用于安全保存,保存成功后输入框自动清空,不留明文痕迹)。
|
|
64
|
+
6. 点击 **保存 (Save)** 即可实时生效,无需重启!
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### 方式二:环境变量与配置文件配置
|
|
69
|
+
|
|
70
|
+
如果你使用 Headless 模式或希望通过环境配置初始化:
|
|
71
|
+
|
|
72
|
+
1. **设置 API Key 环境变量**(默认变量名为 `WEB_SEARCH_ENHANCED_API`):
|
|
73
|
+
```bash
|
|
74
|
+
export WEB_SEARCH_ENHANCED_API="sk-your-api-key-here"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
2. **在 `cordis.yml` 中声明配置**(可选):
|
|
78
|
+
```yaml
|
|
79
|
+
- id: web-search-enhanced
|
|
80
|
+
name: dsh-web-search-enhanced
|
|
81
|
+
config:
|
|
82
|
+
modelMode: configured
|
|
83
|
+
protocol: anthropic-messages
|
|
84
|
+
baseURL: https://api.deepseek.com/anthropic/v1
|
|
85
|
+
model: deepseek-v4-flash
|
|
86
|
+
apiKeyEnv: WEB_SEARCH_ENHANCED_API
|
|
87
|
+
maxTokens: 4096
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 💡 常用场景配置示例
|
|
93
|
+
|
|
94
|
+
你可以直接参考以下常见场景的配置参数,轻松接入各厂商自身提供的原生搜索功能:
|
|
95
|
+
|
|
96
|
+
### 1. DeepSeek 官方搜索(默认推荐)
|
|
97
|
+
使用 DeepSeek 官方兼容 Anthropic 协议的服务端搜索,速度快且成本极低:
|
|
98
|
+
- **模型路由 (modelMode)**: `固定配置 (configured)`
|
|
99
|
+
- **API 协议 (protocol)**: `Anthropic Messages v1`
|
|
100
|
+
- **接口地址 (baseURL)**: `https://api.deepseek.com/anthropic/v1`
|
|
101
|
+
- **模型标识 (model)**: `deepseek-v4-flash`
|
|
102
|
+
- **API Key**: 填入你的 DeepSeek API Key
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### 2. Anthropic 官方 Claude 联网搜索
|
|
107
|
+
直接调用 Claude 官方 Messages API 原生内置的 `web_search` 服务端搜索能力:
|
|
108
|
+
- **模型路由 (modelMode)**: `固定配置 (configured)`
|
|
109
|
+
- **API 协议 (protocol)**: `Anthropic Messages v1`
|
|
110
|
+
- **接口地址 (baseURL)**: `https://api.anthropic.com/v1`
|
|
111
|
+
- **模型标识 (model)**: `claude-3-7-sonnet-20250219` 或 `claude-3-5-sonnet-20241022`
|
|
112
|
+
- **内部搜索标识符 (toolIdentifier)**: 留空(默认使用 `web_search_20250305`)
|
|
113
|
+
- **API Key**: 填入你的 Anthropic API Key
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
### 3. OpenAI Responses API
|
|
118
|
+
使用 OpenAI 官方 Responses API 内置的原生联网搜索工具:
|
|
119
|
+
- **模型路由 (modelMode)**: `固定配置 (configured)`
|
|
120
|
+
- **API 协议 (protocol)**: `OpenAI Responses API`
|
|
121
|
+
- **接口地址 (baseURL)**: `https://api.openai.com/v1`
|
|
122
|
+
- **模型标识 (model)**: `gpt-4o`
|
|
123
|
+
- **搜索上下文大小 (searchContextSize)**: `中 (medium)`(可选 `low` / `medium` / `high`)
|
|
124
|
+
- **API Key**: 填入你的 OpenAI API Key
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### 4. OpenAI Chat Completions 专用搜索模型 / 兼容中转网关
|
|
129
|
+
使用 OpenAI 官方搜索模型(如 `gpt-4o-search`)或各类第三方兼容网关(如 OneAPI、NewAPI、OpenRouter 等)提供的原生搜索支持:
|
|
130
|
+
- **模型路由 (modelMode)**: `固定配置 (configured)`
|
|
131
|
+
- **API 协议 (protocol)**: `OpenAI Chat Completions API`
|
|
132
|
+
- **接口地址 (baseURL)**: `https://api.openai.com/v1`(或中转网关地址,如 `https://api.your-proxy.com/v1`)
|
|
133
|
+
- **模型标识 (model)**: 目标搜索模型标识(如 `gpt-4o-search`)
|
|
134
|
+
- **Chat 搜索能力 (chatSearchMode)**: `官方专用搜索模型 (search-model)`(若网关使用自定义字段可切换为 `vendor-options`)
|
|
135
|
+
- **API Key**: 填入网关或官方 API Key
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### 5. 跟随当前会话模型(自动继承厂商搜索)
|
|
140
|
+
让搜索自动使用当前 Agent 会话正在对话的模型供应商与协议:
|
|
141
|
+
- **模型路由 (modelMode)**: `当前会话模型 (current-session)`
|
|
142
|
+
- **兜底搜索模型 (fallbackModel)**: `deepseek-v4-flash`(当当前模型不支持搜索协议或未解析到凭据时自动平滑回退)
|
|
143
|
+
- **API 协议 / 接口地址 / API Key**: 自动跟随当前会话的 LLM 路由配置
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## ⚙️ 详细配置参数表
|
|
148
|
+
|
|
149
|
+
| 参数名 | 对应 Web 界面 | 默认值 | 可选值 / 格式 | 说明 |
|
|
150
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
151
|
+
| `modelMode` | 模型路由 | `configured` | `configured` (固定配置)<br>`current-session` (跟随当前会话) | 决定搜索使用固定的独立模型,还是跟随当前会话的模型与协议。 |
|
|
152
|
+
| `protocol` | API 协议 | `anthropic-messages` | `anthropic-messages`<br>`openai-responses`<br>`openai-chat-completions` | 固定路由或兜底路由使用的上游 HTTP 协议。 |
|
|
153
|
+
| `baseURL` | 接口基础地址 | `https://api.deepseek.com/anthropic/v1` | 绝对 HTTP(S) URL | 上游接口的基础 URL。若末尾未包含协议端点后缀,插件会自动补全。 |
|
|
154
|
+
| `model` | 模型标识 | `deepseek-v4-flash` | 字符串 | 固定路由使用的模型 ID,或无会话模型时的默认模型。 |
|
|
155
|
+
| `fallbackModel` | 兜底搜索模型 | 留空(默认同 `model`) | 字符串 | 仅跟随模式:当无法解析当前会话路由时所采用的兜底模型。 |
|
|
156
|
+
| `apiKeyEnv` | API Key 环境变量 | `WEB_SEARCH_ENHANCED_API` | 环境变量名 | 读取 API Key 的凭据引用名称。 |
|
|
157
|
+
| `apiKey` | API Key | 无 | 字符串(密钥) | Web 设置界面提供的一次性保存输入框,安全存入 DSH 凭据中心后自动清空。 |
|
|
158
|
+
| `toolIdentifier` | 内部搜索标识符 | 依协议自动推导 | 字符串 | 上游搜索工具/选项字段名。留空时自动适配官方默认名称。 |
|
|
159
|
+
| `maxTokens` | 最大输出 Token | `4096` | 正整数 | 单次搜索请求的最大输出 Token 数。 |
|
|
160
|
+
| `maxUses` | 最大搜索次数 | `5` | 正整数 | 仅 Anthropic 协议:单次请求允许服务端调用的最大搜索次数。 |
|
|
161
|
+
| `apiVersion` | Anthropic API 版本 | `2023-06-01` | 字符串 | 仅 Anthropic 协议:写入 `anthropic-version` 请求头的版本标识。 |
|
|
162
|
+
| `chatSearchMode` | Chat 搜索能力 | `search-model` | `search-model`<br>`vendor-options` | 仅 Chat 协议:官方专用搜索模型模式,或第三方网关自定义选项字段模式。 |
|
|
163
|
+
| `searchContextSize` | 搜索上下文大小 | 上游默认 | `low` / `medium` / `high` | 仅 OpenAI 协议:搜索上下文预算大小。 |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 🔒 凭据安全与隐私设计
|
|
168
|
+
|
|
169
|
+
1. **凭据安全隔离**:Web 设置卡片中的 API Key 输入框仅作为向 `ctx.remote.credentials.set()` 发送写入请求的临时通道。一旦保存成功,输入框立即清空,DSH 的普通 settings document 中**绝对不会存储明文密钥**。
|
|
170
|
+
2. **防凭据泄漏机制**:所有向上游发起的请求均设置 `redirect: 'error'`。若上游服务发生 HTTP 重定向,请求会立即终止,严防 `Authorization` 或 `x-api-key` 被第三方捕获。
|
|
171
|
+
3. **URL 规范校验**:接口地址 (`baseURL`) 严格禁止包含用户名、密码、Query 参数或 Hash 锚点,杜绝敏感信息通过 URL 泄漏。
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## ❓ 常见问题 (FAQ)
|
|
176
|
+
|
|
177
|
+
<details>
|
|
178
|
+
<summary><strong>Q: 为什么推荐直接使用模型供应商的内置搜索,而不是配置第三方搜索引擎?</strong></summary>
|
|
179
|
+
|
|
180
|
+
**A**:
|
|
181
|
+
1. **省心省钱**:直接使用已有的大模型 API 凭据,无需单独注册、付费订阅第三方搜索服务(如 Tavily、Bing API 等);
|
|
182
|
+
2. **质量与整合度高**:大模型供应商(如 Anthropic、OpenAI、DeepSeek)针对模型理解对抓取内容和上下文预算进行了专门优化;
|
|
183
|
+
3. **低延迟**:检索与正文提取由模型服务端直接完成,避免了客户端多次网络往返。
|
|
184
|
+
</details>
|
|
185
|
+
|
|
186
|
+
<details>
|
|
187
|
+
<summary><strong>Q: 安装插件后,模型会知道底层搜索协议改变了吗?</strong></summary>
|
|
188
|
+
|
|
189
|
+
**A**: 不会。DSH 内部采用分层架构,模型端看到的依然是原生的 `web_search` 工具,参数与返回值结构完全保持一致。插件仅在后台将搜索请求代理至你配置的上游协议,并把来源与引用归一化为 DSH 标准的 `WebSearchResult`。
|
|
190
|
+
</details>
|
|
191
|
+
|
|
192
|
+
<details>
|
|
193
|
+
<summary><strong>Q: 搜索时提示 <code>WEB_PROVIDER_CREDENTIAL_MISSING</code> 怎么办?</strong></summary>
|
|
194
|
+
|
|
195
|
+
**A**: 表示未找到有效的 API Key。请在 Web 界面「设置 → 插件 → Web Search Enhanced」卡片中输入 API Key 并点击保存,或者在启动 DSH 前配置环境变量(如 `export WEB_SEARCH_ENHANCED_API="sk-..."`)。
|
|
196
|
+
</details>
|
|
197
|
+
|
|
198
|
+
<details>
|
|
199
|
+
<summary><strong>Q: 跟随模式 (current-session) 在什么情况下会触发兜底?</strong></summary>
|
|
200
|
+
|
|
201
|
+
**A**: 当出现以下情况时会自动使用 `fallbackModel` 兜底:
|
|
202
|
+
- 当前 Agent 尚未选择具体模型;
|
|
203
|
+
- 当前模型的 Provider 未配置接口地址或协议不匹配;
|
|
204
|
+
- 获取当前路由的 ModelInfo 失败。
|
|
205
|
+
</details>
|
|
206
|
+
|
|
207
|
+
<details>
|
|
208
|
+
<summary><strong>Q: 如何卸载插件或还原到原生搜索?</strong></summary>
|
|
209
|
+
|
|
210
|
+
**A**: 运行以下命令从 Profile 中移除插件并重启 DSH:
|
|
211
|
+
```bash
|
|
212
|
+
dsh plugin --profile web remove dsh-web-search-enhanced
|
|
213
|
+
```
|
|
214
|
+
</details>
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 🛠️ 本地开发与调试
|
|
219
|
+
|
|
220
|
+
如果你希望基于本项目进行二次开发或贡献代码:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# 克隆仓库并安装依赖
|
|
224
|
+
git clone https://github.com/your-username/dsh-web-search-enhanced.git
|
|
225
|
+
cd dsh-web-search-enhanced
|
|
67
226
|
pnpm install
|
|
227
|
+
|
|
228
|
+
# 运行全套检查(类型检查 + 单元测试 + 构建 + 打包契约验证)
|
|
68
229
|
pnpm run check
|
|
69
|
-
~~~
|
|
70
230
|
|
|
71
|
-
|
|
231
|
+
# 单独运行单元测试
|
|
232
|
+
npx vitest run
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
技术架构与详细设计文档请参阅 [docs/design.zh-CN.md](docs/design.zh-CN.md)。
|
|
236
|
+
|
|
237
|
+
---
|
|
72
238
|
|
|
73
|
-
|
|
74
|
-
XDG_DATA_HOME=$PWD/.xdg/data XDG_CONFIG_HOME=$PWD/.xdg/config PNPM_HOME=$PWD/.pnpm-home pnpm install
|
|
75
|
-
~~~
|
|
239
|
+
## 📄 开源许可证
|
|
76
240
|
|
|
77
|
-
|
|
241
|
+
本项目基于 [MIT License](LICENSE) 开源。
|
package/docs/design.zh-CN.md
CHANGED
|
@@ -23,7 +23,7 @@ flowchart LR
|
|
|
23
23
|
N --> T
|
|
24
24
|
~~~
|
|
25
25
|
|
|
26
|
-
Host 入口通过 <code>
|
|
26
|
+
Host 入口通过 <code>ctx.inject(['settings'], ...)</code> 注入并调用 <code>settingsCtx.settings.installSection()</code> 注册 <code>web-search-enhanced</code> namespace。每次搜索开始时只读取一次 resolved settings,保证一次调用不会混用更新前后的 endpoint、协议和 Token 上限。provider ID 在注册时固定;实时设置不能修改该字段,否则 <code>ctx.web</code> 的 provider 选择会与已注册对象不一致。
|
|
27
27
|
|
|
28
28
|
Client 入口把相同 namespace 绑定到 <code>settings.plugin.item</code> keyed slot。插件配置页只在 Host 暴露 namespace 时渲染卡片,未加载 Host 插件时不会出现不可用配置项。
|
|
29
29
|
|
package/docs/harness-contract.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Source of truth
|
|
4
4
|
|
|
5
|
-
Extracted from DeepSeek Harness
|
|
5
|
+
Extracted from DeepSeek Harness release `0.1.2-alpha.2` (commit `3f1b46a5db`). Installable dependencies use the npm package line `>=0.1.1-rc.2`; source and registry baselines are intentionally recorded separately.
|
|
6
6
|
|
|
7
7
|
Representative sources:
|
|
8
8
|
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
2
2
|
import { launchEnvironmentOf } from "@deepseek-ai/dsh-launch-environment";
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
|
-
import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
5
4
|
import { WebError } from "@deepseek-ai/dsh-web";
|
|
6
5
|
//#region lib/types/protocols.js
|
|
7
6
|
const ENDPOINT_SUFFIX = {
|
|
@@ -23,7 +22,7 @@ function buildWireRequest(config, query, apiKey) {
|
|
|
23
22
|
const commonHeaders = {
|
|
24
23
|
"accept": "application/json",
|
|
25
24
|
"content-type": "application/json",
|
|
26
|
-
"user-agent": "dsh-web-search-enhanced/0.0.
|
|
25
|
+
"user-agent": "dsh-web-search-enhanced/0.0.2"
|
|
27
26
|
};
|
|
28
27
|
switch (config.protocol) {
|
|
29
28
|
case "anthropic-messages": return {
|
|
@@ -270,27 +269,28 @@ var EnhancedSearchProvider = class {
|
|
|
270
269
|
});
|
|
271
270
|
} catch (error) {
|
|
272
271
|
if (signal?.aborted === true || isAbortError(error)) throw aborted(signal, error);
|
|
273
|
-
throw
|
|
272
|
+
throw searchEndpointError(wire.endpoint, config.apiKeyEnv, `dsh-web-search-enhanced: ${config.protocol} request failed: ${String(error)}`, error);
|
|
274
273
|
}
|
|
275
274
|
if (!response.ok) {
|
|
276
275
|
let detail = `HTTP ${response.status}`;
|
|
277
276
|
try {
|
|
278
277
|
const payload = await response.json();
|
|
279
278
|
const root = typeof payload === "object" && payload !== null ? payload : void 0;
|
|
280
|
-
const
|
|
281
|
-
|
|
279
|
+
const error = typeof root?.error === "object" && root.error !== null ? root.error : void 0;
|
|
280
|
+
const candidate = error?.message ?? (typeof error === "string" ? error : void 0) ?? root?.message;
|
|
281
|
+
if (typeof candidate === "string" && candidate.length > 0) detail = `${detail}: ${candidate}`;
|
|
282
282
|
} catch (error) {
|
|
283
283
|
if (signal?.aborted === true || isAbortError(error)) throw aborted(signal, error);
|
|
284
284
|
}
|
|
285
|
-
throw
|
|
285
|
+
throw searchEndpointError(wire.endpoint, config.apiKeyEnv, `dsh-web-search-enhanced: upstream API error (${detail})`);
|
|
286
286
|
}
|
|
287
287
|
try {
|
|
288
288
|
const payload = await response.json();
|
|
289
289
|
return parseSearchResponse(config.protocol, payload);
|
|
290
290
|
} catch (error) {
|
|
291
291
|
if (signal?.aborted === true || isAbortError(error)) throw aborted(signal, error);
|
|
292
|
-
|
|
293
|
-
throw
|
|
292
|
+
const message = error instanceof WebError ? error.message : `dsh-web-search-enhanced: unprocessable ${config.protocol} response: ${String(error)}`;
|
|
293
|
+
throw searchEndpointError(wire.endpoint, config.apiKeyEnv, message, error);
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
296
|
};
|
|
@@ -311,6 +311,10 @@ async function resolveCredential(pending, signal) {
|
|
|
311
311
|
});
|
|
312
312
|
});
|
|
313
313
|
}
|
|
314
|
+
/** Add endpoint recovery instructions to failures that occur after request dispatch begins. */
|
|
315
|
+
function searchEndpointError(endpoint, apiKeyEnv, message, cause) {
|
|
316
|
+
return new WebError(`${message}\n\nThe web search request used endpoint ${JSON.stringify(endpoint)}. Search endpoint configuration is separate from chat. If that endpoint is not intended, guide the user to Settings > Plugins > Plugin configuration > Web Search Enhanced, where they can change and save Endpoint base URL. If that settings page is unavailable, the user can set ${apiKeyEnv.length > 0 ? apiKeyEnv : "WEB_SEARCH_ENHANCED_API"} or configure web-search-enhanced.baseURL to a trusted search endpoint. Only the user should choose or change the endpoint.`, "WEB_PROVIDER_ERROR", cause === void 0 ? void 0 : { cause });
|
|
317
|
+
}
|
|
314
318
|
function throwIfAborted(signal) {
|
|
315
319
|
if (signal?.aborted === true) throw aborted(signal);
|
|
316
320
|
}
|
|
@@ -331,7 +335,7 @@ const DEFAULT_MODEL = "deepseek-v4-flash";
|
|
|
331
335
|
/** Credential reference owned by this plugin's fixed and fallback routes. */
|
|
332
336
|
const DEFAULT_API_KEY_ENV = "WEB_SEARCH_ENHANCED_API";
|
|
333
337
|
/** Settings namespace paired with the plugin configuration card. */
|
|
334
|
-
const SETTINGS_NAMESPACE =
|
|
338
|
+
const SETTINGS_NAMESPACE = "web-search-enhanced";
|
|
335
339
|
/** Cordis plugin name used by loader diagnostics. */
|
|
336
340
|
const name = "web-search-enhanced";
|
|
337
341
|
/** The web seam this provider contributes to. */
|
|
@@ -453,11 +457,28 @@ function createProvider(config = {}, fetcher = globalThis.fetch) {
|
|
|
453
457
|
const resolved = resolveConfig(config);
|
|
454
458
|
return new EnhancedSearchProvider(() => resolved, fetcher);
|
|
455
459
|
}
|
|
460
|
+
function installPluginSettings(ctx, ns, schema, entry, hooks) {
|
|
461
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
462
|
+
const settings = settingsCtx.settings;
|
|
463
|
+
if (typeof settings?.installSection === "function") settings.installSection(ctx, ns, schema, entry, hooks);
|
|
464
|
+
else if (typeof settings?.register === "function") {
|
|
465
|
+
const scope = settings.register(ns, schema, {
|
|
466
|
+
base: entry,
|
|
467
|
+
...hooks.validate === void 0 ? {} : { validate: hooks.validate }
|
|
468
|
+
});
|
|
469
|
+
hooks.setSource(() => scope.get());
|
|
470
|
+
hooks.onChange();
|
|
471
|
+
scope.watch(() => {
|
|
472
|
+
hooks.onChange();
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
}
|
|
456
477
|
/** Register the provider and its live Web Profile settings section. */
|
|
457
478
|
function apply(ctx, config) {
|
|
458
479
|
const providerId = resolveConfig(config).providerId;
|
|
459
480
|
let current = () => config;
|
|
460
|
-
|
|
481
|
+
installPluginSettings(ctx, SETTINGS_NAMESPACE, Config, config, {
|
|
461
482
|
setSource: (source) => {
|
|
462
483
|
current = source;
|
|
463
484
|
},
|
package/lib/types/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare const DEFAULT_MODEL = "deepseek-v4-flash";
|
|
|
15
15
|
/** Credential reference owned by this plugin's fixed and fallback routes. */
|
|
16
16
|
export declare const DEFAULT_API_KEY_ENV = "WEB_SEARCH_ENHANCED_API";
|
|
17
17
|
/** Settings namespace paired with the plugin configuration card. */
|
|
18
|
-
export declare const SETTINGS_NAMESPACE
|
|
18
|
+
export declare const SETTINGS_NAMESPACE = "web-search-enhanced";
|
|
19
19
|
/** Cordis plugin name used by loader diagnostics. */
|
|
20
20
|
export declare const name = "web-search-enhanced";
|
|
21
21
|
/** The web seam this provider contributes to. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-web-search-enhanced",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Multi-protocol web_search provider for DeepSeek Harness",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"cordis.patch.yml",
|
|
31
31
|
"docs",
|
|
32
32
|
"README.md",
|
|
33
|
+
"CHANGELOG.md",
|
|
33
34
|
"LICENSE"
|
|
34
35
|
],
|
|
35
36
|
"publishConfig": {
|
|
@@ -117,6 +118,7 @@
|
|
|
117
118
|
"anthropic",
|
|
118
119
|
"openai"
|
|
119
120
|
],
|
|
121
|
+
"author": "Yurzi",
|
|
120
122
|
"scripts": {
|
|
121
123
|
"clean": "node scripts/clean.mjs",
|
|
122
124
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|