dsh-web-search-plugin 0.3.1 → 0.4.1
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 +20 -1
- package/README.md +6 -5
- package/cordis.patch.yml +6 -4
- package/lib/brave.js +4 -6
- package/lib/client.js +17 -17
- package/lib/index.js +11 -15
- package/lib/shared.js +1 -1
- package/package.json +8 -10
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
本项目的重要变更都记录在此。格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [0.4.1] - 2026-09-10
|
|
6
|
+
|
|
7
|
+
### 变更
|
|
8
|
+
|
|
9
|
+
- **适配 DeepSeek Harness `0.1.5-rc.1`**:四个 DSH peerDependencies 提升到 `^0.1.5-rc.1`,Node.js 运行要求对齐为 `^22.19.0 || >=24.0.0`。
|
|
10
|
+
- 浏览器端显式注入 `remote.credentials`,避免 API remote 尚未挂载时访问凭据服务的启动顺序竞态。
|
|
11
|
+
- Bundle 覆盖 `web.config` 时保留上游 `fetchProvider: http`,不再因切换搜索 provider 而隐式清除抓取 provider。
|
|
12
|
+
- Brave 的 `proxy` 仅作为 provider 级显式覆盖;留空时继承 DSH 的全局代理分发器,统一支持 `HTTP_PROXY` / `HTTPS_PROXY` / `ALL_PROXY` / `NO_PROXY`。
|
|
13
|
+
- 版本号及 `User-Agent` 更新为 `0.4.1`。
|
|
14
|
+
|
|
15
|
+
## [0.4.0] - 2026-09-02
|
|
16
|
+
|
|
17
|
+
### 变更
|
|
18
|
+
|
|
19
|
+
- **适配 DeepSeek Harness 最新 main(`0.1.2-alpha.4`)**:`@deepseek-ai/dsh-settings` 已移除顶层 `installSettingsSection` / `settingsNamespace`,Host 侧改为在 `ctx.inject(['settings'])` 后调用 `settingsCtx.settings.installSection(ctx, ...)`;settings namespace 直接使用普通字符串。
|
|
20
|
+
- **浏览器端移除对 `@deepseek-ai/dsh-client-runtime` / 旧 `connection` 的依赖**:该包已不在最新 Harness workspace / 客户端模块表中。`createSnapshotStore` 改从平台常驻模块 `@deepseek-ai/dsh-client-store` 导入;`dsh.client.inject` 与客户端 `inject` 对齐为 `slots` / `locale` / `remote` / `settingsScope`。
|
|
21
|
+
- **凭据远端接口迁移到 `ctx.remote`**:`credentials.describe(refs[])` / `set(ref, value)` 使用最新 Remote 参数与响应形状(`{ ok, value }`);凭据变更事件从 `credentials/updated` 改为 `credentials/reference-updated`;不再经旧 `connection.api` 调用。
|
|
22
|
+
- peerDependencies 中 dsh 包版本从 `0.1.0-rc.7` 提升到 `0.1.2-alpha.4`;`@deepseek-ai/cordis` / `@deepseek-ai/schemastery` 分别对齐 `^4.0.2` / `^3.18.2`;版本号升至 `0.4.0`,`User-Agent` 同步。
|
|
23
|
+
|
|
5
24
|
## [0.3.1] - 2026-08-30
|
|
6
25
|
|
|
7
26
|
### 修复
|
|
@@ -99,7 +118,7 @@
|
|
|
99
118
|
|
|
100
119
|
### 修复
|
|
101
120
|
|
|
102
|
-
- **客户端 bundle 缺少 `exports.inject`**(`lib/client.js`)。浏览器插件原先只导出 `apply`,cordis 的 `fiber.inject` 为空,访问 `ctx.locale` 等服务会抛 `cannot get property "locale" without inject`。现在导出 `inject = ["slots", "locale", "
|
|
121
|
+
- **客户端 bundle 缺少 `exports.inject`**(`lib/client.js`)。浏览器插件原先只导出 `apply`,cordis 的 `fiber.inject` 为空,访问 `ctx.locale` 等服务会抛 `cannot get property "locale" without inject`。现在导出 `inject = ["slots", "locale", "remote", "settingsScope"]`。
|
|
103
122
|
- **插件卡片的 slot 注册**(`lib/client.js`)。卡片按 rc.6 的 `id`/`order` 形状注册进 `settings.plugin.item`;该 slot 从 rc.6+ 起是 keyed 的,必须带 `key: "dsh-web-search-plugin"`。
|
|
104
123
|
- **`CardForm.field("apiKey")` 崩溃**(`lib/client.js`)。只写凭据字段没有 section spec,对 `undefined` 调用 `spec.format(...)` 会在卡片投影时抛 `Cannot read properties of undefined (reading 'format')`。已加上 secret 字段分支(对齐官方 `CardForm`)。
|
|
105
124
|
- **`dsh.client.inject` 补上 `@deepseek-ai/dsh-client-ui-slots`**(`package.json`),与社区插件的加载集合一致。
|
package/README.md
CHANGED
|
@@ -17,19 +17,20 @@
|
|
|
17
17
|
|
|
18
18
|
## 特性
|
|
19
19
|
|
|
20
|
-
- 与官方 `@deepseek-ai/dsh-web-search-deepseek` 相同的提供方约定:`inject: ['web']` + `
|
|
20
|
+
- 与官方 `@deepseek-ai/dsh-web-search-deepseek` 相同的提供方约定:`inject: ['web']` + `ctx.settings.installSection` + `ctx.web.registerSearchProvider`。
|
|
21
21
|
- 顶层 **设置 → 网页搜索** 分区:两列布局、未保存草稿、保存 toast;结果数量为 1–20 下拉。
|
|
22
22
|
- **默认引擎为 DeepSeek(官方)**:新装 / 未显式改动时,搜索直接走 `deepseek-official`,不再依赖 keyless 的 Tavily。
|
|
23
23
|
- 纯 REST 后端由**静态元数据表 + 通用后端**驱动,新增 provider 即"表里加一行 + 官方跳转链接",无定制执行代码。
|
|
24
24
|
- Tavily keyless 无需密钥即可用;Brave 需要订阅 token(若本机已有 `BRAVE_API_KEY` 凭据,可直接复用)。
|
|
25
25
|
- Tavily keyed / Brave 在设置卡展示额度进度条(DeepSeek 官方与 Tavily keyless / 其余 REST 后端不展示)。
|
|
26
26
|
- 各引擎结果都规范化为接缝的 `WebSearchResult`(可选 `content` + `sources[]`),按 URL 去重。
|
|
27
|
-
- 设置段 `dsh-web-search-plugin` 通过
|
|
27
|
+
- 设置段 `dsh-web-search-plugin` 通过 dsh 的 `settings.installSection` 注册、由 `settings.describe()` 动态暴露,不需要宿主白名单补丁,也不需要自建回环 settings 桥。
|
|
28
28
|
- 错误映射为 `WEB_PROVIDER_ERROR` / `WEB_ABORTED` / `WEB_PROVIDER_CREDENTIAL_MISSING`。
|
|
29
29
|
|
|
30
30
|
## 运行要求
|
|
31
31
|
|
|
32
|
-
- DeepSeek Harness `0.1.
|
|
32
|
+
- DeepSeek Harness `0.1.5-rc.1` 或兼容版本
|
|
33
|
+
- Node.js `^22.19.0` 或 `>=24.0.0`
|
|
33
34
|
- pnpm,用于通过 `dsh plugin` 把插件装进 profile
|
|
34
35
|
|
|
35
36
|
## 安装
|
|
@@ -72,7 +73,7 @@ dsh plugin --profile web add dsh-web-search-plugin
|
|
|
72
73
|
| `country` | — | Brave 的 `country`(ISO 两位码,如 `cn`);留空使用 Brave 默认 |
|
|
73
74
|
| `searchLang` | — | Brave 的 `search_lang`(如 `zh-hans`);留空使用 Brave 默认 |
|
|
74
75
|
| `freshness` | — | Brave 的 `freshness`:`pd` / `pw` / `pm` / `py` |
|
|
75
|
-
| `proxy` | — | Brave 使用的 HTTP(S)
|
|
76
|
+
| `proxy` | — | Brave 使用的 HTTP(S) 代理覆盖;留空继承 DSH 的全局 `HTTP_PROXY` / `HTTPS_PROXY` / `ALL_PROXY` / `NO_PROXY` 策略 |
|
|
76
77
|
| `serperApiKey` / `serperApiKeyEnv` / `serperBaseURL` | — / `SERPER_API_KEY` / — | Serper 的 key 字面量 / 凭据引用名 / 端点覆盖 |
|
|
77
78
|
| `serpapiApiKey` / `serpapiApiKeyEnv` / `serpapiBaseURL` | — / `SERPAPI_API_KEY` / — | SerpApi 的 key 字面量 / 凭据引用名 / 端点覆盖 |
|
|
78
79
|
| `exaApiKey` / `exaApiKeyEnv` / `exaBaseURL` | — / `EXA_API_KEY` / — | Exa 的 key 字面量 / 凭据引用名 / 端点覆盖 |
|
|
@@ -189,7 +190,7 @@ dsh plugin --profile web remove @dsh-ltctfer/dsh-web-search-brave
|
|
|
189
190
|
npm run check
|
|
190
191
|
```
|
|
191
192
|
|
|
192
|
-
客户端 bundle 必须保持 `window.__ModuleLoader__.load({ id, factory })` 线格式 — 由 `dsh-client-modules` 加载,不是打包器。必须同时导出 `apply` 和 `inject`(`slots`、`locale`、`
|
|
193
|
+
客户端 bundle 必须保持 `window.__ModuleLoader__.load({ id, factory })` 线格式 — 由 `dsh-client-modules` 加载,不是打包器。必须同时导出 `apply` 和 `inject`(`slots`、`locale`、`remote`、`settingsScope`),并把分区注册进 `settings.section`(`id: "web-search"`)。
|
|
193
194
|
|
|
194
195
|
## 发布
|
|
195
196
|
|
package/cordis.patch.yml
CHANGED
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
# installs the package as a plain library: no loader row, no Host apply, no
|
|
4
4
|
# `/plugins/<name>/client.js`.
|
|
5
5
|
#
|
|
6
|
-
# `searchProvider`
|
|
7
|
-
# targeted row's whole `config`. The
|
|
8
|
-
# wins if it later overrides `web`. The
|
|
9
|
-
# backend (DeepSeek / Tavily / Brave) is the
|
|
6
|
+
# `searchProvider` and the upstream `fetchProvider` are restated in full
|
|
7
|
+
# because a Cordis patch replaces the targeted row's whole `config`. The
|
|
8
|
+
# profile's own cordis.patch.yml still wins if it later overrides `web`. The
|
|
9
|
+
# seam id is `dsh-web-search`; the backend (DeepSeek / Tavily / Brave) is the
|
|
10
|
+
# plugin's own `provider` setting.
|
|
10
11
|
- id: web
|
|
11
12
|
name: '@deepseek-ai/dsh-web'
|
|
12
13
|
config:
|
|
13
14
|
searchProvider: dsh-web-search
|
|
15
|
+
fetchProvider: http
|
|
14
16
|
|
|
15
17
|
# This plugin re-hosts the DeepSeek backend, so the in-box DeepSeek host
|
|
16
18
|
# plugin is redundant: disabling it removes its `deepseek-official` provider
|
package/lib/brave.js
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { ProxyAgent } from "undici";
|
|
14
14
|
import { WebError } from "@deepseek-ai/dsh-web";
|
|
15
|
-
import { launchEnvironmentOf } from "@deepseek-ai/dsh-launch-environment";
|
|
16
15
|
import { MAX_RESULTS_CAP, USER_AGENT, isAbortError, isPositiveInteger, resolveApiKey, resolveSecret, searchAborted, throwIfSearchAborted } from "./shared.js";
|
|
17
16
|
|
|
18
17
|
/** Default Brave Search API web-results endpoint. */
|
|
@@ -123,9 +122,9 @@ export class BraveSearchProvider {
|
|
|
123
122
|
}
|
|
124
123
|
|
|
125
124
|
/**
|
|
126
|
-
* Cached undici ProxyAgent for
|
|
127
|
-
*
|
|
128
|
-
*
|
|
125
|
+
* Cached undici ProxyAgent for an explicit provider-level proxy override.
|
|
126
|
+
* With no override, fetch inherits the dispatcher installed by DSH so its
|
|
127
|
+
* HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY policy remains intact.
|
|
129
128
|
*/
|
|
130
129
|
dispatcher(options) {
|
|
131
130
|
const proxy = options.proxy;
|
|
@@ -142,7 +141,6 @@ export class BraveSearchProvider {
|
|
|
142
141
|
|
|
143
142
|
/** Project the plugin section into Brave backend options. */
|
|
144
143
|
export function resolveBraveOptions(ctx, config) {
|
|
145
|
-
const environment = launchEnvironmentOf(ctx);
|
|
146
144
|
return {
|
|
147
145
|
...resolveSecret(ctx, {
|
|
148
146
|
literal: config.braveApiKey,
|
|
@@ -153,6 +151,6 @@ export function resolveBraveOptions(ctx, config) {
|
|
|
153
151
|
country: config.country,
|
|
154
152
|
searchLang: config.searchLang,
|
|
155
153
|
freshness: config.freshness,
|
|
156
|
-
proxy: config.proxy
|
|
154
|
+
proxy: config.proxy
|
|
157
155
|
};
|
|
158
156
|
}
|
package/lib/client.js
CHANGED
|
@@ -21,7 +21,7 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
var exports = module.exports;
|
|
22
22
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
23
23
|
let react = require("react");
|
|
24
|
-
let
|
|
24
|
+
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
25
25
|
|
|
26
26
|
/** Settings namespace of this plugin. */
|
|
27
27
|
const NS = "dsh-web-search-plugin";
|
|
@@ -132,7 +132,7 @@ window.__ModuleLoader__.load({
|
|
|
132
132
|
freshnessMonth: "Past month",
|
|
133
133
|
freshnessYear: "Past year",
|
|
134
134
|
proxy: "Proxy",
|
|
135
|
-
proxyPlaceholder: "Leave blank to
|
|
135
|
+
proxyPlaceholder: "Leave blank to inherit the DSH proxy settings.",
|
|
136
136
|
deepseekApiKeyEnv: "Credential reference",
|
|
137
137
|
deepseekApiKeyEnvHint: "Name of the credential/env var resolved for DeepSeek search.",
|
|
138
138
|
deepseekBaseURL: "Endpoint",
|
|
@@ -228,7 +228,7 @@ window.__ModuleLoader__.load({
|
|
|
228
228
|
freshnessMonth: "过去一月",
|
|
229
229
|
freshnessYear: "过去一年",
|
|
230
230
|
proxy: "代理",
|
|
231
|
-
proxyPlaceholder: "
|
|
231
|
+
proxyPlaceholder: "留空继承 DSH 全局代理设置",
|
|
232
232
|
deepseekApiKeyEnv: "凭据引用名",
|
|
233
233
|
deepseekApiKeyEnvHint: "DeepSeek 搜索解析的凭据/环境变量名。",
|
|
234
234
|
deepseekBaseURL: "接口地址",
|
|
@@ -334,9 +334,9 @@ window.__ModuleLoader__.load({
|
|
|
334
334
|
* spec and are written through the credentials domain.
|
|
335
335
|
*/
|
|
336
336
|
var SearchCardForm = class {
|
|
337
|
-
constructor(scope,
|
|
337
|
+
constructor(scope, remote) {
|
|
338
338
|
this.scope = scope;
|
|
339
|
-
this.
|
|
339
|
+
this.remote = remote;
|
|
340
340
|
this.specs = new Map([
|
|
341
341
|
choiceField("provider"),
|
|
342
342
|
choiceField("mode"),
|
|
@@ -391,7 +391,7 @@ window.__ModuleLoader__.load({
|
|
|
391
391
|
this.readCredential();
|
|
392
392
|
}
|
|
393
393
|
bind(project) {
|
|
394
|
-
const store = (0,
|
|
394
|
+
const store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(project());
|
|
395
395
|
this.listeners.add(() => {
|
|
396
396
|
store.set(project());
|
|
397
397
|
});
|
|
@@ -591,12 +591,12 @@ window.__ModuleLoader__.load({
|
|
|
591
591
|
}
|
|
592
592
|
let response;
|
|
593
593
|
try {
|
|
594
|
-
response = await this.
|
|
594
|
+
response = await this.remote.credentials.describe([ref]);
|
|
595
595
|
} catch (_credentialReadFailure) {
|
|
596
596
|
return;
|
|
597
597
|
}
|
|
598
|
-
if (!response.
|
|
599
|
-
const view = response.
|
|
598
|
+
if (!response.ok || ref !== this.refOf()) return;
|
|
599
|
+
const view = response.value[ref];
|
|
600
600
|
const next = {
|
|
601
601
|
ref,
|
|
602
602
|
configured: view?.configured ?? false,
|
|
@@ -619,7 +619,8 @@ window.__ModuleLoader__.load({
|
|
|
619
619
|
ref = rest !== void 0 ? this.restKeyRef(rest) : this.tavilyRef();
|
|
620
620
|
}
|
|
621
621
|
try {
|
|
622
|
-
await this.
|
|
622
|
+
const response = await this.remote.credentials.set(ref, value);
|
|
623
|
+
if (!response.ok) return false;
|
|
623
624
|
} catch (_credentialWriteFailure) {}
|
|
624
625
|
await this.readCredential();
|
|
625
626
|
return this.credential.ref === ref ? this.credential.configured : true;
|
|
@@ -628,10 +629,10 @@ window.__ModuleLoader__.load({
|
|
|
628
629
|
|
|
629
630
|
/** Bridges the plugin scope and the credentials domain onto the card. */
|
|
630
631
|
var SearchCardController = class {
|
|
631
|
-
constructor(scope,
|
|
632
|
+
constructor(scope, remote) {
|
|
632
633
|
this.scope = scope;
|
|
633
|
-
this.
|
|
634
|
-
this.form = new SearchCardForm(scope,
|
|
634
|
+
this.remote = remote;
|
|
635
|
+
this.form = new SearchCardForm(scope, remote);
|
|
635
636
|
this.store = this.form.bind(() => this.projection());
|
|
636
637
|
scope.subscribe(() => {
|
|
637
638
|
this.form.readCredential();
|
|
@@ -1150,11 +1151,10 @@ window.__ModuleLoader__.load({
|
|
|
1150
1151
|
|
|
1151
1152
|
/** Mount the top-level "Web search" settings section. */
|
|
1152
1153
|
function apply(ctx) {
|
|
1153
|
-
const { api } = ctx.get("connection");
|
|
1154
1154
|
const t = ctx.locale.bind(NS);
|
|
1155
1155
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-web-search-plugin: card dictionaries");
|
|
1156
|
-
const controller = new SearchCardController(ctx.settingsScope.bind({ namespace: NS }),
|
|
1157
|
-
ctx.effect(() => ctx.remote.$on("credentials/updated", (ref) => {
|
|
1156
|
+
const controller = new SearchCardController(ctx.settingsScope.bind({ namespace: NS }), ctx.remote);
|
|
1157
|
+
ctx.effect(() => ctx.remote.$on("credentials/reference-updated", (ref) => {
|
|
1158
1158
|
controller.form.refreshCredential(ref);
|
|
1159
1159
|
}), "dsh-web-search-plugin: credential invalidations");
|
|
1160
1160
|
ctx.effect(() => usageStore.start(), "dsh-web-search-plugin: usage poll");
|
|
@@ -1168,7 +1168,7 @@ window.__ModuleLoader__.load({
|
|
|
1168
1168
|
}, makeSection(ctx, controller)));
|
|
1169
1169
|
}
|
|
1170
1170
|
|
|
1171
|
-
const inject = ["slots", "locale", "
|
|
1171
|
+
const inject = ["slots", "locale", "remote", "remote.credentials", "settingsScope"];
|
|
1172
1172
|
|
|
1173
1173
|
exports.apply = apply;
|
|
1174
1174
|
exports.inject = inject;
|
package/lib/index.js
CHANGED
|
@@ -17,8 +17,6 @@
|
|
|
17
17
|
* @module dsh-web-search-plugin
|
|
18
18
|
*/
|
|
19
19
|
import z from "@deepseek-ai/schemastery";
|
|
20
|
-
import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
21
|
-
import { launchEnvironmentOf } from "@deepseek-ai/dsh-launch-environment";
|
|
22
20
|
import { MAX_RESULTS_CAP } from "./shared.js";
|
|
23
21
|
import { TAVILY_DEFAULT_API_KEY_ENV, TAVILY_DEFAULT_BASE_URL, TavilySearchProvider, resolveTavilyOptions } from "./tavily.js";
|
|
24
22
|
import { BRAVE_DEFAULT_API_KEY_ENV, BRAVE_DEFAULT_BASE_URL, BraveSearchProvider, resolveBraveOptions } from "./brave.js";
|
|
@@ -34,6 +32,8 @@ const SEARCH_PROVIDER_ID = "dsh-web-search";
|
|
|
34
32
|
const name = "dsh-web-search-plugin";
|
|
35
33
|
/** The web seam this provider registers into. */
|
|
36
34
|
const inject = ["web"];
|
|
35
|
+
/** Settings namespace carrying this plugin's backend switch and options. */
|
|
36
|
+
const WEB_SEARCH_SETTINGS_NAMESPACE = "dsh-web-search-plugin";
|
|
37
37
|
|
|
38
38
|
/** Plugin config (all optional — `apply` fills defaults). */
|
|
39
39
|
const Config = z.object({
|
|
@@ -67,7 +67,7 @@ const Config = z.object({
|
|
|
67
67
|
searchLang: z.string().default(""),
|
|
68
68
|
/** Optional Brave `freshness` (`pd` / `pw` / `pm` / `py`). */
|
|
69
69
|
freshness: z.string().default(""),
|
|
70
|
-
/** Optional HTTP(S) proxy URL for Brave
|
|
70
|
+
/** Optional HTTP(S) proxy URL for Brave; blank inherits DSH's global proxy policy. */
|
|
71
71
|
proxy: z.string().default(""),
|
|
72
72
|
/** Literal Serper API key; prefer {@link serperApiKeyEnv}. */
|
|
73
73
|
serperApiKey: z.string().role("secret").default(""),
|
|
@@ -117,11 +117,6 @@ const Config = z.object({
|
|
|
117
117
|
maxUses: z.number().step(1).min(1).default(5)
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
/** Settings namespace carrying this plugin's backend switch and options. */
|
|
121
|
-
const WEB_SEARCH_SETTINGS_NAMESPACE = settingsNamespace("dsh-web-search-plugin");
|
|
122
|
-
/** @deprecated Use {@link WEB_SEARCH_SETTINGS_NAMESPACE}. */
|
|
123
|
-
const WEB_SEARCH_TAVILY_SETTINGS_NAMESPACE = WEB_SEARCH_SETTINGS_NAMESPACE;
|
|
124
|
-
|
|
125
120
|
/**
|
|
126
121
|
* One seam-facing provider whose `id` stays `dsh-web-search`. The active
|
|
127
122
|
* backend is read from the live settings section on every `available` /
|
|
@@ -177,7 +172,7 @@ function resolveOptions(ctx, config) {
|
|
|
177
172
|
// metadata row's default is not enough (self-hosted SearXNG, proxied
|
|
178
173
|
// providers, custom key refs).
|
|
179
174
|
const keySourceByProvider = {
|
|
180
|
-
brave: { literal: config.braveApiKey, envName: config.braveApiKeyEnv ?? BRAVE_DEFAULT_API_KEY_ENV, baseURL: config.braveBaseURL ?? "", proxy: config.proxy
|
|
175
|
+
brave: { literal: config.braveApiKey, envName: config.braveApiKeyEnv ?? BRAVE_DEFAULT_API_KEY_ENV, baseURL: config.braveBaseURL ?? "", proxy: config.proxy ?? "" },
|
|
181
176
|
tavily: { literal: config.apiKey, envName: config.apiKeyEnv ?? TAVILY_DEFAULT_API_KEY_ENV, baseURL: config.baseURL ?? "" },
|
|
182
177
|
serper: { literal: config.serperApiKey, envName: config.serperApiKeyEnv ?? "SERPER_API_KEY", baseURL: config.serperBaseURL ?? "" },
|
|
183
178
|
serpapi: { literal: config.serpapiApiKey, envName: config.serpapiApiKeyEnv ?? "SERPAPI_API_KEY", baseURL: config.serpapiBaseURL ?? "" },
|
|
@@ -254,11 +249,13 @@ function sendJson(res, statusCode, data) {
|
|
|
254
249
|
/** Register the dispatched search provider with `ctx.web`. */
|
|
255
250
|
function apply(ctx, config) {
|
|
256
251
|
let current = () => config;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
252
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
253
|
+
settingsCtx.settings.installSection(ctx, WEB_SEARCH_SETTINGS_NAMESPACE, Config, config, {
|
|
254
|
+
setSource: (source) => {
|
|
255
|
+
current = source;
|
|
256
|
+
},
|
|
257
|
+
onChange: () => {}
|
|
258
|
+
});
|
|
262
259
|
});
|
|
263
260
|
const live = () => resolveOptions(ctx, current());
|
|
264
261
|
const usage = new UsageTracker({
|
|
@@ -335,7 +332,6 @@ export {
|
|
|
335
332
|
TavilySearchProvider,
|
|
336
333
|
UsageTracker,
|
|
337
334
|
WEB_SEARCH_SETTINGS_NAMESPACE,
|
|
338
|
-
WEB_SEARCH_TAVILY_SETTINGS_NAMESPACE,
|
|
339
335
|
apply,
|
|
340
336
|
findProvider,
|
|
341
337
|
inject,
|
package/lib/shared.js
CHANGED
|
@@ -7,7 +7,7 @@ import { launchEnvironmentOf } from "@deepseek-ai/dsh-launch-environment";
|
|
|
7
7
|
import { WebError } from "@deepseek-ai/dsh-web";
|
|
8
8
|
|
|
9
9
|
/** Attribution header sent on every request. */
|
|
10
|
-
export const USER_AGENT = "dsh-web-search-plugin/0.
|
|
10
|
+
export const USER_AGENT = "dsh-web-search-plugin/0.4.1";
|
|
11
11
|
/** Shared cap: Tavily `max_results` and Brave `count` both accept 1..20. */
|
|
12
12
|
export const MAX_RESULTS_CAP = 20;
|
|
13
13
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-web-search-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Unified web search for the DeepSeek Harness seam (ctx.web): DeepSeek (official), Tavily, Brave, Serper, SerpApi, Exa, SearXNG, Scavio, and Firecrawl backends",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh-plugin",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"LICENSE"
|
|
25
25
|
],
|
|
26
26
|
"engines": {
|
|
27
|
-
"node": ">=
|
|
27
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
28
28
|
},
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
@@ -43,9 +43,7 @@
|
|
|
43
43
|
"client": {
|
|
44
44
|
"platform": "web",
|
|
45
45
|
"inject": [
|
|
46
|
-
"@deepseek-ai/dsh-client-connection",
|
|
47
46
|
"@deepseek-ai/dsh-client-locale",
|
|
48
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
49
47
|
"@deepseek-ai/dsh-client-ui-settings",
|
|
50
48
|
"@deepseek-ai/dsh-client-ui-slots",
|
|
51
49
|
"@deepseek-ai/dsh-api-remotes"
|
|
@@ -59,12 +57,12 @@
|
|
|
59
57
|
"undici": "^6.21.0"
|
|
60
58
|
},
|
|
61
59
|
"peerDependencies": {
|
|
62
|
-
"@deepseek-ai/dsh-web": "^0.1.
|
|
63
|
-
"@deepseek-ai/dsh-credentials": "^0.1.
|
|
64
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
65
|
-
"@deepseek-ai/dsh-launch-environment": "^0.1.
|
|
66
|
-
"@deepseek-ai/schemastery": "^3.18.
|
|
67
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
60
|
+
"@deepseek-ai/dsh-web": "^0.1.5-rc.1",
|
|
61
|
+
"@deepseek-ai/dsh-credentials": "^0.1.5-rc.1",
|
|
62
|
+
"@deepseek-ai/dsh-settings": "^0.1.5-rc.1",
|
|
63
|
+
"@deepseek-ai/dsh-launch-environment": "^0.1.5-rc.1",
|
|
64
|
+
"@deepseek-ai/schemastery": "^3.18.2",
|
|
65
|
+
"@deepseek-ai/cordis": "^4.0.2"
|
|
68
66
|
},
|
|
69
67
|
"license": "MIT",
|
|
70
68
|
"repository": {
|