@dcrays/web-search 0.1.1 → 0.1.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/README.md +2 -2
- package/package.json +2 -2
- package/plugin/index.d.ts +0 -1
- package/plugin/index.js +52 -34
- package/src/api-client.d.ts +4 -4
- package/src/api-client.js +33 -12
- package/src/config/env-config.d.ts +10 -5
- package/src/config/env-config.js +10 -4
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# @dcrays/web-search
|
|
2
2
|
|
|
3
|
-
书灵墨宝的 DSH 联网搜索插件。加载后注册 `web_search`
|
|
3
|
+
书灵墨宝的 DSH 联网搜索插件。加载后注册 `web_search` 工具,把模型搜索请求映射到搜索网关。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
单一发布包同时适用于生产与测试桌面:运行时根据 `mobook.json` 中记录的环境选择搜索网关与 MBHChat 凭据通道;`endpointUrl` 可在 Cordis 插件配置中覆盖。
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcrays/web-search",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "DeepSeek Harness web search plugin for Mobook
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "DeepSeek Harness web search plugin for Mobook",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "plugin/index.js",
|
|
7
7
|
"types": "plugin/index.d.ts",
|
package/plugin/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { Context } from '@deepseek-ai/cordis';
|
|
|
2
2
|
import { Service } from '@deepseek-ai/cordis';
|
|
3
3
|
import z from '@deepseek-ai/schemastery';
|
|
4
4
|
import { type WebSearchRequest, type WebSearchResult } from '../src/index.js';
|
|
5
|
-
export { DEFAULT_BUILD_ENV } from '../src/config/env-config.js';
|
|
6
5
|
export declare const name = "mbh-web-search";
|
|
7
6
|
export declare const inject: string[];
|
|
8
7
|
export interface Config {
|
package/plugin/index.js
CHANGED
|
@@ -9,6 +9,25 @@ import z from "@deepseek-ai/schemastery";
|
|
|
9
9
|
// dist-npm/src/api-client.js
|
|
10
10
|
import { createHmac, randomUUID } from "node:crypto";
|
|
11
11
|
import { readFile } from "node:fs/promises";
|
|
12
|
+
|
|
13
|
+
// dist-npm/src/config/env-config.js
|
|
14
|
+
var ENV_CONFIG = {
|
|
15
|
+
production: {
|
|
16
|
+
channelId: "mbh-chat",
|
|
17
|
+
legacyChannelId: "mbhchat",
|
|
18
|
+
endpointUrl: "https://api-gateway.shuwenda.com/apikey-manage/api/search"
|
|
19
|
+
},
|
|
20
|
+
test: {
|
|
21
|
+
channelId: "mbh-chat-test",
|
|
22
|
+
legacyChannelId: "mbhchat-test",
|
|
23
|
+
endpointUrl: "https://api-gateway.shuwenda.icu/apikey-manage/api/search"
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
function resolveWebSearchEnvironment(value) {
|
|
27
|
+
return value === "production" ? "production" : "test";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// dist-npm/src/api-client.js
|
|
12
31
|
var WebSearchApiError = class extends Error {
|
|
13
32
|
code;
|
|
14
33
|
constructor(code, message, options) {
|
|
@@ -125,23 +144,41 @@ function parseResponse(text, fallbackQuery, service) {
|
|
|
125
144
|
}
|
|
126
145
|
return result;
|
|
127
146
|
}
|
|
147
|
+
function toEndpoint(endpointUrl) {
|
|
148
|
+
let endpoint;
|
|
149
|
+
try {
|
|
150
|
+
endpoint = new URL(endpointUrl);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
throw new WebSearchApiError("INVALID_CONFIG", "\u641C\u7D22\u670D\u52A1\u5730\u5740\u914D\u7F6E\u4E0D\u6B63\u786E\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u68C0\u67E5\u63D2\u4EF6\u914D\u7F6E\u3002", { cause: error });
|
|
153
|
+
}
|
|
154
|
+
if (!["http:", "https:"].includes(endpoint.protocol)) {
|
|
155
|
+
throw new WebSearchApiError("INVALID_CONFIG", "\u641C\u7D22\u670D\u52A1\u5730\u5740\u4EC5\u652F\u6301 HTTP \u6216 HTTPS\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u68C0\u67E5\u63D2\u4EF6\u914D\u7F6E\u3002");
|
|
156
|
+
}
|
|
157
|
+
return endpoint;
|
|
158
|
+
}
|
|
128
159
|
var WebSearchApiClient = class {
|
|
129
160
|
config;
|
|
130
|
-
|
|
161
|
+
environments;
|
|
131
162
|
fetchImpl;
|
|
132
163
|
readFileImpl;
|
|
133
164
|
nowSeconds;
|
|
134
165
|
nonce;
|
|
135
166
|
constructor(config, dependencies = {}) {
|
|
136
167
|
this.config = config;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
168
|
+
const environments = config.environments ?? ENV_CONFIG;
|
|
169
|
+
const override = config.endpointOverride?.trim();
|
|
170
|
+
this.environments = {
|
|
171
|
+
production: {
|
|
172
|
+
endpoint: toEndpoint(override || environments.production.endpointUrl),
|
|
173
|
+
channelId: environments.production.channelId,
|
|
174
|
+
legacyChannelId: environments.production.legacyChannelId
|
|
175
|
+
},
|
|
176
|
+
test: {
|
|
177
|
+
endpoint: toEndpoint(override || environments.test.endpointUrl),
|
|
178
|
+
channelId: environments.test.channelId,
|
|
179
|
+
legacyChannelId: environments.test.legacyChannelId
|
|
180
|
+
}
|
|
181
|
+
};
|
|
145
182
|
for (const [name2, value] of [
|
|
146
183
|
["timeoutMs", config.timeoutMs],
|
|
147
184
|
["maxResponseBytes", config.maxResponseBytes],
|
|
@@ -178,7 +215,9 @@ var WebSearchApiClient = class {
|
|
|
178
215
|
} catch (error) {
|
|
179
216
|
throw new WebSearchApiError("MISSING_CREDENTIALS", "\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u58A8\u5B9D\u8FD0\u884C\u914D\u7F6E\uFF0C\u8BF7\u786E\u8BA4\u5BA2\u6237\u7AEF\u5DF2\u6B63\u5E38\u521D\u59CB\u5316\u540E\u91CD\u8BD5\u3002", { cause: error });
|
|
180
217
|
}
|
|
181
|
-
const
|
|
218
|
+
const environment = resolveWebSearchEnvironment(record(metadata)?.environment);
|
|
219
|
+
const resolved = this.environments[environment];
|
|
220
|
+
const credentials = resolveSearchCredentials(metadata, resolved.channelId, resolved.legacyChannelId);
|
|
182
221
|
const call = async (service) => {
|
|
183
222
|
const timestamp = String(this.nowSeconds());
|
|
184
223
|
const nonce = this.nonce();
|
|
@@ -207,7 +246,7 @@ ${nonce}`;
|
|
|
207
246
|
const effectiveSignal = requestSignal(signal, this.config.timeoutMs);
|
|
208
247
|
let response;
|
|
209
248
|
try {
|
|
210
|
-
response = await this.fetchImpl(
|
|
249
|
+
response = await this.fetchImpl(resolved.endpoint, {
|
|
211
250
|
method: "POST",
|
|
212
251
|
headers: { accept: "application/json", "content-type": "application/json" },
|
|
213
252
|
body: JSON.stringify(body),
|
|
@@ -277,24 +316,6 @@ function createWebSearchTool(search) {
|
|
|
277
316
|
// dist-npm/src/index.js
|
|
278
317
|
var MBH_WEB_SEARCH_SERVICE_KEY = "mbhWebSearch";
|
|
279
318
|
|
|
280
|
-
// dist-npm/src/config/env-config.js
|
|
281
|
-
var ENV_CONFIG = {
|
|
282
|
-
production: {
|
|
283
|
-
packageName: "@dcrays/web-search",
|
|
284
|
-
channelId: "mbh-chat",
|
|
285
|
-
legacyChannelId: "mbhchat",
|
|
286
|
-
endpointUrl: "https://api-gateway.shuwenda.com/apikey-manage/api/search"
|
|
287
|
-
},
|
|
288
|
-
test: {
|
|
289
|
-
packageName: "@dcrays/web-search-test",
|
|
290
|
-
channelId: "mbh-chat-test",
|
|
291
|
-
legacyChannelId: "mbhchat-test",
|
|
292
|
-
endpointUrl: "https://api-gateway.shuwenda.icu/apikey-manage/api/search"
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
var DEFAULT_BUILD_ENV = "production";
|
|
296
|
-
var ACTIVE_ENV_CONFIG = ENV_CONFIG[DEFAULT_BUILD_ENV];
|
|
297
|
-
|
|
298
319
|
// dist-npm/plugin/index.js
|
|
299
320
|
var name = "@dcrays/web-search";
|
|
300
321
|
var inject = ["tools"];
|
|
@@ -316,10 +337,8 @@ var MbhWebSearchService = class extends Service {
|
|
|
316
337
|
if (!config.enabled)
|
|
317
338
|
return;
|
|
318
339
|
this.operations = new WebSearchApiClient({
|
|
319
|
-
endpointUrl: config.endpointUrl.trim() || ACTIVE_ENV_CONFIG.endpointUrl,
|
|
320
340
|
metadataPath: resolveMetadataPath(config.metadataPath),
|
|
321
|
-
|
|
322
|
-
legacyChannelId: ACTIVE_ENV_CONFIG.legacyChannelId,
|
|
341
|
+
...config.endpointUrl.trim() ? { endpointOverride: config.endpointUrl.trim() } : {},
|
|
323
342
|
timeoutMs: config.timeoutMs,
|
|
324
343
|
maxResponseBytes: config.maxResponseBytes,
|
|
325
344
|
defaultCount: config.defaultCount,
|
|
@@ -345,13 +364,12 @@ function apply(ctx, config) {
|
|
|
345
364
|
if (!service.isEnabled())
|
|
346
365
|
return () => void 0;
|
|
347
366
|
const unregister = ctx.tools.register(createWebSearchTool(service));
|
|
348
|
-
ctx.logger(name).info("%s plugin loaded with web_search tool
|
|
367
|
+
ctx.logger(name).info("%s plugin loaded with web_search tool", name);
|
|
349
368
|
return unregister;
|
|
350
369
|
}, `${name} lifecycle`);
|
|
351
370
|
}
|
|
352
371
|
export {
|
|
353
372
|
Config,
|
|
354
|
-
DEFAULT_BUILD_ENV,
|
|
355
373
|
MbhWebSearchService,
|
|
356
374
|
apply,
|
|
357
375
|
inject,
|
package/src/api-client.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type EnvConfig, type WebSearchEnvironment } from './config/env-config.js';
|
|
1
2
|
export interface WebSearchRequest {
|
|
2
3
|
query: string;
|
|
3
4
|
count?: number;
|
|
@@ -24,10 +25,9 @@ export interface WebSearchOperations {
|
|
|
24
25
|
search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>;
|
|
25
26
|
}
|
|
26
27
|
export interface WebSearchApiClientConfig {
|
|
27
|
-
endpointUrl: string;
|
|
28
28
|
metadataPath: string;
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
endpointOverride?: string;
|
|
30
|
+
environments?: Record<WebSearchEnvironment, EnvConfig>;
|
|
31
31
|
timeoutMs: number;
|
|
32
32
|
maxResponseBytes: number;
|
|
33
33
|
defaultCount: number;
|
|
@@ -53,7 +53,7 @@ interface SearchCredentials {
|
|
|
53
53
|
export declare function resolveSearchCredentials(metadata: unknown, channelId: string, legacyChannelId: string): SearchCredentials;
|
|
54
54
|
export declare class WebSearchApiClient implements WebSearchOperations {
|
|
55
55
|
private readonly config;
|
|
56
|
-
private readonly
|
|
56
|
+
private readonly environments;
|
|
57
57
|
private readonly fetchImpl;
|
|
58
58
|
private readonly readFileImpl;
|
|
59
59
|
private readonly nowSeconds;
|
package/src/api-client.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHmac, randomUUID } from 'node:crypto';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { ENV_CONFIG, resolveWebSearchEnvironment } from './config/env-config.js';
|
|
3
4
|
export class WebSearchApiError extends Error {
|
|
4
5
|
code;
|
|
5
6
|
constructor(code, message, options) {
|
|
@@ -118,24 +119,42 @@ function parseResponse(text, fallbackQuery, service) {
|
|
|
118
119
|
}
|
|
119
120
|
return result;
|
|
120
121
|
}
|
|
122
|
+
function toEndpoint(endpointUrl) {
|
|
123
|
+
let endpoint;
|
|
124
|
+
try {
|
|
125
|
+
endpoint = new URL(endpointUrl);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
throw new WebSearchApiError('INVALID_CONFIG', '搜索服务地址配置不正确,请联系管理员检查插件配置。', { cause: error });
|
|
129
|
+
}
|
|
130
|
+
if (!['http:', 'https:'].includes(endpoint.protocol)) {
|
|
131
|
+
throw new WebSearchApiError('INVALID_CONFIG', '搜索服务地址仅支持 HTTP 或 HTTPS,请联系管理员检查插件配置。');
|
|
132
|
+
}
|
|
133
|
+
return endpoint;
|
|
134
|
+
}
|
|
121
135
|
export class WebSearchApiClient {
|
|
122
136
|
config;
|
|
123
|
-
|
|
137
|
+
environments;
|
|
124
138
|
fetchImpl;
|
|
125
139
|
readFileImpl;
|
|
126
140
|
nowSeconds;
|
|
127
141
|
nonce;
|
|
128
142
|
constructor(config, dependencies = {}) {
|
|
129
143
|
this.config = config;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
144
|
+
const environments = config.environments ?? ENV_CONFIG;
|
|
145
|
+
const override = config.endpointOverride?.trim();
|
|
146
|
+
this.environments = {
|
|
147
|
+
production: {
|
|
148
|
+
endpoint: toEndpoint(override || environments.production.endpointUrl),
|
|
149
|
+
channelId: environments.production.channelId,
|
|
150
|
+
legacyChannelId: environments.production.legacyChannelId
|
|
151
|
+
},
|
|
152
|
+
test: {
|
|
153
|
+
endpoint: toEndpoint(override || environments.test.endpointUrl),
|
|
154
|
+
channelId: environments.test.channelId,
|
|
155
|
+
legacyChannelId: environments.test.legacyChannelId
|
|
156
|
+
}
|
|
157
|
+
};
|
|
139
158
|
for (const [name, value] of [
|
|
140
159
|
['timeoutMs', config.timeoutMs],
|
|
141
160
|
['maxResponseBytes', config.maxResponseBytes],
|
|
@@ -173,7 +192,9 @@ export class WebSearchApiClient {
|
|
|
173
192
|
catch (error) {
|
|
174
193
|
throw new WebSearchApiError('MISSING_CREDENTIALS', '暂时无法读取墨宝运行配置,请确认客户端已正常初始化后重试。', { cause: error });
|
|
175
194
|
}
|
|
176
|
-
const
|
|
195
|
+
const environment = resolveWebSearchEnvironment(record(metadata)?.environment);
|
|
196
|
+
const resolved = this.environments[environment];
|
|
197
|
+
const credentials = resolveSearchCredentials(metadata, resolved.channelId, resolved.legacyChannelId);
|
|
177
198
|
const call = async (service) => {
|
|
178
199
|
const timestamp = String(this.nowSeconds());
|
|
179
200
|
const nonce = this.nonce();
|
|
@@ -199,7 +220,7 @@ export class WebSearchApiClient {
|
|
|
199
220
|
const effectiveSignal = requestSignal(signal, this.config.timeoutMs);
|
|
200
221
|
let response;
|
|
201
222
|
try {
|
|
202
|
-
response = await this.fetchImpl(
|
|
223
|
+
response = await this.fetchImpl(resolved.endpoint, {
|
|
203
224
|
method: 'POST',
|
|
204
225
|
headers: { accept: 'application/json', 'content-type': 'application/json' },
|
|
205
226
|
body: JSON.stringify(body),
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type WebSearchEnvironment = 'production' | 'test';
|
|
2
2
|
export interface EnvConfig {
|
|
3
|
-
packageName: string;
|
|
4
3
|
channelId: string;
|
|
5
4
|
legacyChannelId: string;
|
|
6
5
|
endpointUrl: string;
|
|
7
6
|
}
|
|
8
|
-
export declare const
|
|
9
|
-
export declare const
|
|
10
|
-
|
|
7
|
+
export declare const PACKAGE_NAME = "@dcrays/web-search";
|
|
8
|
+
export declare const ENV_CONFIG: Record<WebSearchEnvironment, EnvConfig>;
|
|
9
|
+
/**
|
|
10
|
+
* Map the desktop runtime environment recorded in mobook.json to the search
|
|
11
|
+
* environment. Development desktops share the test gateway and MBHChat channel.
|
|
12
|
+
* Missing/unknown values fall back to test so a misconfigured desktop never
|
|
13
|
+
* silently reaches the production gateway with test credentials.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveWebSearchEnvironment(value: unknown): WebSearchEnvironment;
|
package/src/config/env-config.js
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
|
+
export const PACKAGE_NAME = '@dcrays/web-search';
|
|
1
2
|
export const ENV_CONFIG = {
|
|
2
3
|
production: {
|
|
3
|
-
packageName: '@dcrays/web-search',
|
|
4
4
|
channelId: 'mbh-chat',
|
|
5
5
|
legacyChannelId: 'mbhchat',
|
|
6
6
|
endpointUrl: 'https://api-gateway.shuwenda.com/apikey-manage/api/search'
|
|
7
7
|
},
|
|
8
8
|
test: {
|
|
9
|
-
packageName: '@dcrays/web-search-test',
|
|
10
9
|
channelId: 'mbh-chat-test',
|
|
11
10
|
legacyChannelId: 'mbhchat-test',
|
|
12
11
|
endpointUrl: 'https://api-gateway.shuwenda.icu/apikey-manage/api/search'
|
|
13
12
|
}
|
|
14
13
|
};
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Map the desktop runtime environment recorded in mobook.json to the search
|
|
16
|
+
* environment. Development desktops share the test gateway and MBHChat channel.
|
|
17
|
+
* Missing/unknown values fall back to test so a misconfigured desktop never
|
|
18
|
+
* silently reaches the production gateway with test credentials.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveWebSearchEnvironment(value) {
|
|
21
|
+
return value === 'production' ? 'production' : 'test';
|
|
22
|
+
}
|