@tonydua/dsh-web-search-exa 0.1.4 → 0.1.5
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.i18n.yaml +2 -2
- package/README.md +150 -19
- package/README.zh.md +124 -15
- package/lib/index.d.ts +386 -0
- package/lib/index.js +315 -230
- package/package.json +26 -12
- package/lib/types/index.d.ts +0 -70
package/README.i18n.yaml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record.
|
|
4
|
-
README.md:
|
|
5
|
-
README.zh.md:
|
|
4
|
+
README.md: 1c5d8f365ee4206b20fa5bd7c07e980266324287
|
|
5
|
+
README.zh.md: 8801d405bc41cace604325a7918152394a5627a6
|
package/README.md
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
**English** | [简体中文](README.zh.md)
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@tonydua/dsh-web-search-exa)
|
|
5
|
+
[](https://www.npmjs.com/package/@tonydua/dsh-web-search-exa)
|
|
6
|
+
[](https://github.com/TonyDua/dsh-web-search-exa/releases/latest)
|
|
6
7
|
[](https://www.npmjs.com/package/@tonydua/dsh-web-search-exa)
|
|
7
8
|
[](LICENSE)
|
|
9
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
10
|
+
[](package.json)
|
|
8
11
|
[](https://github.com/TonyDua/dsh-web-search-exa)
|
|
9
12
|
[](https://github.com/TonyDua/dsh-web-search-exa)
|
|
10
|
-
[](package.json)
|
|
11
|
-
[](https://www.npmjs.com/package/@deepseek-ai/dsh)
|
|
12
13
|
|
|
13
14
|
> Zero-config [Exa](https://exa.ai) web search for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh):
|
|
14
15
|
> **no API key required** — a `WebSearchProvider` for the `ctx.web` seam with an
|
|
@@ -18,17 +19,128 @@ Built with [deepseek-v4-flash](https://api-docs.deepseek.com) inside DeepSeek Ha
|
|
|
18
19
|
|
|
19
20
|
## Supported versions
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
**Every published dsh version from `0.1.2-alpha.2` to `0.1.7-alpha.1` is
|
|
23
|
+
verified**, not merely declared: each one is installed in isolation, the plugin
|
|
24
|
+
is typechecked against that version's own declarations, and the test suite runs
|
|
25
|
+
against it. Reproduce with `bash scripts/compat-matrix.sh`.
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
27
|
+
| dsh line | Verified | Notes |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `0.1.2-alpha.2` … `0.1.2-alpha.5` | ✅ | oldest supported |
|
|
30
|
+
| `0.1.2-rc.1` | ✅ | |
|
|
31
|
+
| `0.1.3-alpha.2` | ✅ | |
|
|
32
|
+
| `0.1.5-alpha.1`, `0.1.5-alpha.2` | ✅ | |
|
|
33
|
+
| `0.1.5-rc.1`, `0.1.5-rc.2`, `0.1.5-rc.3` | ✅ | `0.1.5-rc.2` also verified end to end: a real `dsh --profile headless` task searched through the anonymous MCP path with no API key present |
|
|
34
|
+
| `0.1.6-alpha.1`, `0.1.6-alpha.2` | ✅ | |
|
|
35
|
+
| `0.1.7-alpha.1` | ✅ | settings service changed shape — see below |
|
|
36
|
+
|
|
37
|
+
### Why the peer range looks like that
|
|
38
|
+
|
|
39
|
+
```jsonc
|
|
40
|
+
"@deepseek-ai/dsh-web": ">=0.1.2-alpha.2 || >=0.1.3-alpha.2 || >=0.1.4-0 || >=0.1.5-alpha.1 || >=0.1.6-alpha.1 || >=0.1.7-alpha.1 || >=0.1.8"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
That enumeration is not decoration — it is the only form that installs on **every**
|
|
44
|
+
published version under **both** pnpm and npm. The rule that forces it:
|
|
45
|
+
|
|
46
|
+
> A pre-release version satisfies a range only if some comparator in that range
|
|
47
|
+
> carries a pre-release **on the same `major.minor.patch` tuple**.
|
|
48
|
+
|
|
49
|
+
So `>=0.1.2-rc.1` does **not** match `0.1.5-rc.2` — the tuples differ. A single
|
|
50
|
+
open-ended lower bound therefore cannot cover a project published as a series of
|
|
51
|
+
prereleases, and `*` would accept even a breaking `1.0`. Each `0.1.x` line that
|
|
52
|
+
ever shipped a prerelease needs its own comparator; `>=0.1.8` then carries every
|
|
53
|
+
future stable release, so the list only needs a new entry when dsh opens a new
|
|
54
|
+
`0.1.x` prerelease line.
|
|
55
|
+
|
|
56
|
+
Measured, on the real published tarball:
|
|
57
|
+
|
|
58
|
+
| range | npm installs | pnpm |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `>=0.1.2-rc.1` (the earlier attempt) | **1 / 14** versions | 14 / 14 |
|
|
61
|
+
| enumerated (current) | **14 / 14** versions | 14 / 14 |
|
|
62
|
+
|
|
63
|
+
This was found by testing rather than reasoning: the open-ended range is fine on
|
|
64
|
+
pnpm, which is what `dsh plugin add` uses, and fails on npm for 13 of the 14
|
|
65
|
+
versions with `ERESOLVE`. If you install with npm and hit that on an older
|
|
66
|
+
release of this package, either upgrade, or pass `--legacy-peer-deps`.
|
|
67
|
+
|
|
68
|
+
### What differs across versions
|
|
69
|
+
|
|
70
|
+
Auditing the real export surfaces of all 14 versions found the `ctx.web` seam
|
|
71
|
+
completely stable — `WebError` is exported from `dsh-web` and still extends
|
|
72
|
+
`HarnessError`, `launchEnvironmentOf` is present, and the settings service is
|
|
73
|
+
mounted at `ctx.settings` in every version. Two things do differ:
|
|
74
|
+
|
|
75
|
+
1. **`0.1.7-alpha.1` replaced the settings API.** `SettingsProvider.installSection`
|
|
76
|
+
is gone; the service is now `SettingsForms`, which derives a configuration
|
|
77
|
+
page from the Config schema the Loader already holds for the entry
|
|
78
|
+
(`SettingsDescriptor.schema`, `autoGenerate`). Calling the old method
|
|
79
|
+
unconditionally threw a `TypeError` on that host, so the plugin loaded but
|
|
80
|
+
failed. It now probes for the method, calls it only when present, and
|
|
81
|
+
otherwise does nothing — on `0.1.7+` the Loader's schema is what feeds the
|
|
82
|
+
form, so there is nothing to register.
|
|
83
|
+
2. **`0.1.7-alpha.1` peers `@deepseek-ai/cordis` `^4.0.3`** while the cordis
|
|
84
|
+
`latest` dist-tag still points at `4.0.2`. `4.0.3` is published; the tag is
|
|
85
|
+
simply behind. Install `@deepseek-ai/cordis@4.0.3` alongside a `0.1.7` host.
|
|
86
|
+
The matrix script pins this per version.
|
|
87
|
+
|
|
88
|
+
Also supported with: `@deepseek-ai/dsh-web`, `dsh-settings` (optional),
|
|
89
|
+
`dsh-launch-environment` across that whole range, and Node.js `>=22.19.0` (the
|
|
90
|
+
harness's own floor).
|
|
91
|
+
|
|
92
|
+
### Profile-install note
|
|
93
|
+
|
|
94
|
+
dsh profiles set `autoInstallPeers: false`, and the harness's own services are
|
|
95
|
+
supplied at runtime by the dsh host instead of being resolved by pnpm. Add this
|
|
96
|
+
to the profile's `pnpm-workspace.yaml` so `dsh plugin add` stays warning-free:
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
peerDependencyRules:
|
|
100
|
+
ignoreMissing:
|
|
101
|
+
- '@deepseek-ai/cordis'
|
|
102
|
+
- '@deepseek-ai/dsh-*'
|
|
103
|
+
```
|
|
29
104
|
|
|
30
|
-
|
|
31
|
-
|
|
105
|
+
### Degradation and failover
|
|
106
|
+
|
|
107
|
+
The keyless channel is a shared, best-effort endpoint. The provider reports its
|
|
108
|
+
own health rather than pretending to always work:
|
|
109
|
+
|
|
110
|
+
- 3 consecutive transient failures (5xx, 429, network, unparseable body) open a
|
|
111
|
+
circuit breaker for 5 minutes, during which `available()` returns `false`. One
|
|
112
|
+
successful search closes it again.
|
|
113
|
+
- A 4xx other than 429 does not trip it — that failure would repeat forever, so
|
|
114
|
+
hiding it would only delay the same error.
|
|
115
|
+
- Anonymous 429s raise `WEB_RATE_LIMITED` (not a generic `WEB_PROVIDER_ERROR`)
|
|
116
|
+
with a message naming `EXA_API_KEY`.
|
|
117
|
+
- The keyed REST path ignores the breaker: a paid endpoint's failures are yours
|
|
118
|
+
to see.
|
|
119
|
+
|
|
120
|
+
**Whether that turns into automatic failover is a harness-side decision.** The
|
|
121
|
+
seam picks exactly one usable provider and has no priority chain — with two
|
|
122
|
+
usable providers it raises `WEB_PROVIDER_AMBIGUOUS`. So:
|
|
123
|
+
|
|
124
|
+
- Pinning `searchProvider: exa` gives deterministic selection but *no* fallback:
|
|
125
|
+
when the breaker opens you get `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`.
|
|
126
|
+
- Leaving `searchProvider` unset gives up determinism: a degraded Exa stops
|
|
127
|
+
being a candidate, but if another provider (say `deepseek-official` with a
|
|
128
|
+
valid `DEEPSEEK_API_KEY`) is also usable, the seam reports ambiguity instead
|
|
129
|
+
of choosing it.
|
|
130
|
+
|
|
131
|
+
Pick whichever failure mode you prefer; the plugin cannot choose for you.
|
|
132
|
+
|
|
133
|
+
### Building from source
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
pnpm install
|
|
137
|
+
pnpm run build # tsdown -> lib/index.js + lib/index.d.ts
|
|
138
|
+
pnpm run typecheck # tsc --noEmit
|
|
139
|
+
pnpm test # builds, then runs the node:test suite against lib/
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`src/` is the source of truth; `lib/` is committed because both the published
|
|
143
|
+
tarball and git-based installs consume it.
|
|
32
144
|
|
|
33
145
|
## Features
|
|
34
146
|
|
|
@@ -83,18 +195,36 @@ The anonymous MCP path sends no credentials; attribution rides the
|
|
|
83
195
|
`x-exa-source: dsh-anything` header. Results are normalized to the seam's
|
|
84
196
|
`WebSearchSource` shape (`url`, `title`, `snippet`, `publishedAt`) and the seam
|
|
85
197
|
enforces `maxResults` on the way back. Anonymous usage is rate-limited by Exa:
|
|
86
|
-
an HTTP 429 surfaces as a `
|
|
87
|
-
key (which also switches to
|
|
198
|
+
an HTTP 429 surfaces as a distinct `WEB_RATE_LIMITED` code — not a generic
|
|
199
|
+
provider failure — with a hint to configure an API key (which also switches to
|
|
200
|
+
the REST path automatically).
|
|
88
201
|
|
|
89
202
|
## Installation (into a dsh profile)
|
|
90
203
|
|
|
91
|
-
**One
|
|
92
|
-
|
|
204
|
+
> **One artifact, two doors.** CI packs this version's tarball, verifies it
|
|
205
|
+
> against every supported dsh version, attaches it to the GitHub Release, and
|
|
206
|
+
> publishes **that artifact** to npm — so the release asset and the npm tarball
|
|
207
|
+
> are one file, not two builds that happen to match.
|
|
208
|
+
|
|
209
|
+
**From npm** (v0.1.4+ ships the `dsh.bundle` manifest, so the bundle patch
|
|
210
|
+
inserts the provider row with no manual patch editing):
|
|
93
211
|
|
|
94
212
|
```powershell
|
|
95
213
|
dsh plugin --profile web add @tonydua/dsh-web-search-exa
|
|
96
214
|
```
|
|
97
215
|
|
|
216
|
+
**From the GitHub Release** — the same tarball, for when npm is unreachable:
|
|
217
|
+
|
|
218
|
+
```powershell
|
|
219
|
+
dsh plugin --profile web add https://github.com/TonyDua/dsh-web-search-exa/releases/latest/download/dsh-web-search-exa.tgz
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**From the repository** (tracks `main`, includes work not yet released):
|
|
223
|
+
|
|
224
|
+
```powershell
|
|
225
|
+
dsh plugin --profile web add github:TonyDua/dsh-web-search-exa
|
|
226
|
+
```
|
|
227
|
+
|
|
98
228
|
Restart `dsh web`. **Without an API key** the official DeepSeek search
|
|
99
229
|
provider is unavailable, so the seam auto-selects this provider — fully
|
|
100
230
|
zero-config. **With a key configured**, select Exa explicitly in your own
|
|
@@ -244,9 +374,10 @@ only; a UI card is planned for the next version. Configure through
|
|
|
244
374
|
[In the Web panel](#in-the-web-panel)).
|
|
245
375
|
|
|
246
376
|
**Q: Which dsh versions are supported?**
|
|
247
|
-
|
|
248
|
-
`
|
|
249
|
-
|
|
377
|
+
Every published dsh version from `0.1.2-alpha.2` to `0.1.7-alpha.1`, plus future
|
|
378
|
+
`0.1.8+` stable releases. Each version is installed in isolation, typechecked
|
|
379
|
+
against its own declarations, and run through this package's test suite in CI —
|
|
380
|
+
see [Why the peer range looks like that](#why-the-peer-range-looks-like-that).
|
|
250
381
|
|
|
251
382
|
## Acknowledgements
|
|
252
383
|
|
package/README.zh.md
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | **简体中文**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@tonydua/dsh-web-search-exa)
|
|
6
|
+
[](https://github.com/TonyDua/dsh-web-search-exa/releases/latest)
|
|
7
|
+
[](https://www.npmjs.com/package/@tonydua/dsh-web-search-exa)
|
|
7
8
|
[](LICENSE)
|
|
9
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
10
|
+
[](package.json)
|
|
8
11
|
[](https://github.com/TonyDua/dsh-web-search-exa)
|
|
9
12
|
[](https://github.com/TonyDua/dsh-web-search-exa)
|
|
10
|
-
[](package.json)
|
|
11
|
-
[](https://www.npmjs.com/package/@deepseek-ai/dsh)
|
|
12
13
|
|
|
13
14
|
> 为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(dsh)提供**零配置**的 [Exa](https://exa.ai) 网页搜索:
|
|
14
15
|
> **无需 API key** —— 一个 `ctx.web` seam 的 `WebSearchProvider`,内置匿名 MCP 兜底 + 带 key 的 REST 路径。
|
|
@@ -17,16 +18,110 @@
|
|
|
17
18
|
|
|
18
19
|
## 当前支持的版本
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
**npm 上从 `0.1.2-alpha.2` 到 `0.1.7-alpha.1` 的每一个 dsh 版本都经过实测**,不是只写在文档里:
|
|
22
|
+
每个版本会被独立安装、用**该版本自己的类型声明**做类型检查、并跑完整测试套件。
|
|
23
|
+
复现命令:`bash scripts/compat-matrix.sh`。
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
| dsh 版本线 | 实测 | 说明 |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `0.1.2-alpha.2` … `0.1.2-alpha.5` | ✅ | 最老的受支持基线 |
|
|
28
|
+
| `0.1.2-rc.1` | ✅ | |
|
|
29
|
+
| `0.1.3-alpha.2` | ✅ | |
|
|
30
|
+
| `0.1.5-alpha.1`、`0.1.5-alpha.2` | ✅ | |
|
|
31
|
+
| `0.1.5-rc.1`、`0.1.5-rc.2`、`0.1.5-rc.3` | ✅ | `0.1.5-rc.2` 另有端到端验证:无 API key 下用真实 `dsh --profile headless` 走通匿名 MCP |
|
|
32
|
+
| `0.1.6-alpha.1`、`0.1.6-alpha.2` | ✅ | |
|
|
33
|
+
| `0.1.7-alpha.1` | ✅ | settings 服务改了形态,见下 |
|
|
34
|
+
|
|
35
|
+
### 为什么 peer 范围长这样
|
|
36
|
+
|
|
37
|
+
```jsonc
|
|
38
|
+
"@deepseek-ai/dsh-web": ">=0.1.2-alpha.2 || >=0.1.3-alpha.2 || >=0.1.4-0 || >=0.1.5-alpha.1 || >=0.1.6-alpha.1 || >=0.1.7-alpha.1 || >=0.1.8"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
这串枚举不是装饰,而是**在 pnpm 与 npm 下都能装遍所有已发布版本**的唯一写法。迫使它成立的规则是:
|
|
42
|
+
|
|
43
|
+
> 一个 prerelease 版本要满足某范围,该范围中必须存在一个比较器,其 prerelease 位于
|
|
44
|
+
> **相同的 `major.minor.patch` tuple** 上。
|
|
45
|
+
|
|
46
|
+
所以 `>=0.1.2-rc.1` **匹配不到** `0.1.5-rc.2`——tuple 不同。这意味着单一开区间下界
|
|
47
|
+
无法覆盖"以一串 prerelease 形式发布的项目",而 `*` 又会连未来的破坏性 `1.0` 一起放行。
|
|
48
|
+
凡是发布过 prerelease 的 `0.1.x` 线都需要自己的比较器;`>=0.1.8` 负责承接之后所有
|
|
49
|
+
稳定版,因此只有当 dsh 开出新的 `0.1.x` prerelease 线时才需要追加条目。
|
|
50
|
+
|
|
51
|
+
在**真实发布物**上实测:
|
|
52
|
+
|
|
53
|
+
| 范围 | npm 可安装版本数 | pnpm |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `>=0.1.2-rc.1`(先前写法) | **1 / 14** | 14 / 14 |
|
|
56
|
+
| 枚举写法(当前) | **14 / 14** | 14 / 14 |
|
|
57
|
+
|
|
58
|
+
这个结论是**测出来的,不是推出来的**:开区间在 pnpm(也就是 `dsh plugin add` 实际使用的
|
|
59
|
+
包管理器)下没问题,但在 npm 下会对 14 个版本中的 13 个报 `ERESOLVE`。若你用 npm 安装
|
|
60
|
+
旧版本的本插件时遇到该错误,升级即可,或临时加 `--legacy-peer-deps`。
|
|
61
|
+
|
|
62
|
+
### 各版本之间究竟差在哪
|
|
63
|
+
|
|
64
|
+
我把 14 个版本的**真实导出面**逐个探测过,结论是 `ctx.web` seam **完全稳定**:
|
|
65
|
+
`WebError` 始终由 `dsh-web` 导出且继承 `HarnessError`,`launchEnvironmentOf` 始终存在,
|
|
66
|
+
`ctx.settings` 在每个版本都被挂载。真正有差异的只有两处:
|
|
67
|
+
|
|
68
|
+
1. **`0.1.7-alpha.1` 换掉了 settings API。** `SettingsProvider.installSection` 被移除,
|
|
69
|
+
服务变为 `SettingsForms`,它直接从 Loader 已持有的 Config schema 派生配置页
|
|
70
|
+
(`SettingsDescriptor.schema`、`autoGenerate`)。旧代码无条件调用该方法会在该版本上抛
|
|
71
|
+
`TypeError`——插件能加载但会失败。现在改为探测该方法:存在才调用,不存在则什么都不做;
|
|
72
|
+
在 `0.1.7+` 上由 Loader 的 schema 驱动表单,插件无需注册任何东西。
|
|
73
|
+
2. **`0.1.7-alpha.1` 依赖 `@deepseek-ai/cordis` `^4.0.3`**,而 cordis 的 `latest`
|
|
74
|
+
dist-tag 仍指向 `4.0.2`。`4.0.3` 已发布,只是 tag 落后。搭配 `0.1.7` 宿主时请安装
|
|
75
|
+
`@deepseek-ai/cordis@4.0.3`。矩阵脚本已按版本固化这一点。
|
|
76
|
+
|
|
77
|
+
同样支持:`@deepseek-ai/dsh-web`、`dsh-settings`(可选)、`dsh-launch-environment`
|
|
78
|
+
覆盖上述整个范围;Node.js `>=22.19.0`(与 harness 自身下限一致)。
|
|
79
|
+
|
|
80
|
+
### profile 安装注意事项
|
|
81
|
+
|
|
82
|
+
dsh profile 默认 `autoInstallPeers: false`,且 harness 自身的服务由 dsh 宿主在运行时
|
|
83
|
+
提供、并不经 pnpm 解析。把下面这段加进 profile 的 `pnpm-workspace.yaml`,
|
|
84
|
+
`dsh plugin add` 就不会再报警告:
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
peerDependencyRules:
|
|
88
|
+
ignoreMissing:
|
|
89
|
+
- '@deepseek-ai/cordis'
|
|
90
|
+
- '@deepseek-ai/dsh-*'
|
|
91
|
+
```
|
|
28
92
|
|
|
29
|
-
|
|
93
|
+
### 降级与回退
|
|
94
|
+
|
|
95
|
+
免 key 通道是共享的尽力而为端点。本 provider 会如实汇报自身健康状况,而不是假装永远可用:
|
|
96
|
+
|
|
97
|
+
- 连续 3 次瞬时失败(5xx、429、网络错误、响应体无法解析)会打开熔断器并冷却 5 分钟,
|
|
98
|
+
期间 `available()` 返回 `false`;任意一次成功搜索即关闭熔断器。
|
|
99
|
+
- 429 以外的 4xx **不会**触发熔断——这类失败会永远重复,把它藏进冷却期只是推迟同一个错误。
|
|
100
|
+
- 匿名通道的 429 抛出 `WEB_RATE_LIMITED`(而非笼统的 `WEB_PROVIDER_ERROR`),
|
|
101
|
+
错误信息里直接点名 `EXA_API_KEY`。
|
|
102
|
+
- 配了 key 的 REST 路径不受熔断影响:付费端点的失败应当让你看到。
|
|
103
|
+
|
|
104
|
+
**但"是否真的自动回退"取决于 harness 侧。** seam 只会选中唯一一个可用 provider,
|
|
105
|
+
并不存在优先级链——同时存在多个可用 provider 时会抛 `WEB_PROVIDER_AMBIGUOUS`。因此:
|
|
106
|
+
|
|
107
|
+
- 写死 `searchProvider: exa`:选择确定,但**没有**回退;熔断打开时得到
|
|
108
|
+
`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`。
|
|
109
|
+
- 不写 `searchProvider`:牺牲确定性。Exa 降级后确实不再是候选,但如果另一个
|
|
110
|
+
provider(比如带有效 `DEEPSEEK_API_KEY` 的 `deepseek-official`)也可用,
|
|
111
|
+
seam 会报"多个可用"而不是替你挑一个。
|
|
112
|
+
|
|
113
|
+
两种失败模式各有利弊,插件无法替你做这个决定。
|
|
114
|
+
|
|
115
|
+
### 从源码构建
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
pnpm install
|
|
119
|
+
pnpm run build # tsdown -> lib/index.js + lib/index.d.ts
|
|
120
|
+
pnpm run typecheck # tsc --noEmit
|
|
121
|
+
pnpm test # 先构建,再对 lib/ 跑 node:test 套件
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`src/` 是唯一事实来源;`lib/` 仍然提交进仓库,因为 npm 发布包与基于 git 的安装都依赖它。
|
|
30
125
|
|
|
31
126
|
## 特性
|
|
32
127
|
|
|
@@ -63,16 +158,30 @@ DeepSeek Harness 自带官方 Exa 提供方 [`@deepseek-ai/dsh-web-search-exa`](
|
|
|
63
158
|
| 配置了 `apiKey` / `EXA_API_KEY` | REST `POST /search`,`Authorization: Bearer` | `https://api.exa.ai/search`(可用 `baseURL` 配置) |
|
|
64
159
|
| 未配置任何 key | 匿名 MCP `tools/call web_search_exa`(JSON-RPC 2.0,无凭据) | `https://mcp.exa.ai/mcp`(可配置) |
|
|
65
160
|
|
|
66
|
-
匿名 MCP 路径不发送任何凭据,来源标识通过 `x-exa-source: dsh-anything` 头携带。结果按 seam 的 `WebSearchSource` 形状规范化(`url`、`title`、`snippet`、`publishedAt`),`maxResults` 由 seam 在返回路径上强制执行。匿名使用受 Exa 限流:HTTP 429
|
|
161
|
+
匿名 MCP 路径不发送任何凭据,来源标识通过 `x-exa-source: dsh-anything` 头携带。结果按 seam 的 `WebSearchSource` 形状规范化(`url`、`title`、`snippet`、`publishedAt`),`maxResults` 由 seam 在返回路径上强制执行。匿名使用受 Exa 限流:HTTP 429 会以独立的 `WEB_RATE_LIMITED` 码呈现(而非笼统的 provider 失败),并提示配置 API key(配置后自动切换到 REST 路径)。
|
|
67
162
|
|
|
68
163
|
## 安装(装入 dsh profile)
|
|
69
164
|
|
|
70
|
-
|
|
165
|
+
> **同一个产物,两个入口。** CI 打包本版本的 tarball、在**每一个**受支持的 dsh 版本上验证、把它挂到 GitHub Release,并把**这个产物本身**发布到 npm——因此 Release 附件与 npm 上的 tarball 是同一个文件,而不是两次恰好一致的构建。
|
|
166
|
+
|
|
167
|
+
**从 npm 安装**(v0.1.4+ 自带 `dsh.bundle` manifest,bundle patch 会自动插入 provider 行,无需手动改 patch):
|
|
71
168
|
|
|
72
169
|
```powershell
|
|
73
170
|
dsh plugin --profile web add @tonydua/dsh-web-search-exa
|
|
74
171
|
```
|
|
75
172
|
|
|
173
|
+
**从 GitHub Release 安装**——同一份 tarball,npm 不可达时用:
|
|
174
|
+
|
|
175
|
+
```powershell
|
|
176
|
+
dsh plugin --profile web add https://github.com/TonyDua/dsh-web-search-exa/releases/latest/download/dsh-web-search-exa.tgz
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**从仓库安装**(跟随 `main`,包含尚未发布的改动):
|
|
180
|
+
|
|
181
|
+
```powershell
|
|
182
|
+
dsh plugin --profile web add github:TonyDua/dsh-web-search-exa
|
|
183
|
+
```
|
|
184
|
+
|
|
76
185
|
重启 `dsh web` 生效。**无 API key 时**官方 DeepSeek 搜索提供方不可用,seam 会自动选中本插件——完全零配置。**配了 key 时**,需在你的 `$DSH_HOME/profiles/web/cordis.patch.yml`(在 bundle patch 之后应用)里显式选中 Exa:
|
|
77
186
|
|
|
78
187
|
```yaml
|
|
@@ -175,7 +284,7 @@ dsh plugin --profile web add ../plugins/dsh-web-search-exa
|
|
|
175
284
|
本版本只在服务端注册了 `web-search-exa` 设置命名空间;UI 卡片计划在下一版本提供。现阶段通过 `cordis.patch.yml` 或环境变量配置(见[在 Web 面板中的呈现](#在-web-面板中的呈现))。
|
|
176
285
|
|
|
177
286
|
**Q: 支持哪些 dsh 版本?**
|
|
178
|
-
|
|
287
|
+
`0.1.2-alpha.2` 到 `0.1.7-alpha.1` 之间**每一个**已发布的 dsh 版本,以及未来的 `0.1.8+` 稳定版。每个版本都会在 CI 里被独立安装、用该版本自己的类型声明做类型检查,并跑一遍本包的测试套件——见[为什么 peer 范围长这样](#为什么-peer-范围长这样)。
|
|
179
288
|
|
|
180
289
|
## 致谢(Acknowledgements)
|
|
181
290
|
|