@dcrays/web-search 0.1.2 → 0.1.3-beta.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 +1 -1
- package/package.json +1 -1
- package/plugin/index.d.ts +1 -3
- package/plugin/index.js +37 -65
- package/src/api-client.d.ts +2 -5
- package/src/api-client.js +28 -35
- package/src/config/env-config.d.ts +0 -14
- package/src/config/env-config.js +0 -21
- package/src/tools.js +1 -1
package/README.md
CHANGED
package/package.json
CHANGED
package/plugin/index.d.ts
CHANGED
|
@@ -6,8 +6,6 @@ export declare const name = "mbh-web-search";
|
|
|
6
6
|
export declare const inject: string[];
|
|
7
7
|
export interface Config {
|
|
8
8
|
enabled: boolean;
|
|
9
|
-
endpointUrl: string;
|
|
10
|
-
metadataPath: string;
|
|
11
9
|
timeoutMs: number;
|
|
12
10
|
maxResponseBytes: number;
|
|
13
11
|
defaultCount: number;
|
|
@@ -26,5 +24,5 @@ export declare class MbhWebSearchService extends Service {
|
|
|
26
24
|
isEnabled(): boolean;
|
|
27
25
|
search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>;
|
|
28
26
|
}
|
|
29
|
-
export declare function resolveMetadataPath(
|
|
27
|
+
export declare function resolveMetadataPath(): string;
|
|
30
28
|
export declare function apply(ctx: Context, config: Config): void;
|
package/plugin/index.js
CHANGED
|
@@ -1,33 +1,14 @@
|
|
|
1
1
|
import { createRequire as __mobookCreateRequire } from 'node:module'; const require = __mobookCreateRequire(import.meta.url);
|
|
2
2
|
|
|
3
|
-
// dist
|
|
3
|
+
// dist/plugin/index.js
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
import { Service } from "@deepseek-ai/cordis";
|
|
6
6
|
import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
7
7
|
import z from "@deepseek-ai/schemastery";
|
|
8
8
|
|
|
9
|
-
// dist
|
|
9
|
+
// dist/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
|
|
31
12
|
var WebSearchApiError = class extends Error {
|
|
32
13
|
code;
|
|
33
14
|
constructor(code, message, options) {
|
|
@@ -46,20 +27,26 @@ function record(value) {
|
|
|
46
27
|
function nonEmptyString(value) {
|
|
47
28
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
48
29
|
}
|
|
49
|
-
function resolveSearchCredentials(metadata
|
|
30
|
+
function resolveSearchCredentials(metadata) {
|
|
50
31
|
const root = record(metadata);
|
|
51
|
-
const plugins = record(root?.plugins);
|
|
52
32
|
const hardware = record(root?.hardware);
|
|
33
|
+
const account = record(root?.account);
|
|
53
34
|
const deviceId = nonEmptyString(hardware?.fingerprint);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return { userId, botToken, deviceId };
|
|
60
|
-
}
|
|
35
|
+
const userIdValue = account?.userId;
|
|
36
|
+
const userId = typeof userIdValue === "number" && Number.isSafeInteger(userIdValue) ? String(userIdValue) : nonEmptyString(userIdValue);
|
|
37
|
+
const botToken = nonEmptyString(account?.botToken);
|
|
38
|
+
if (userId && botToken && deviceId)
|
|
39
|
+
return { userId, botToken, deviceId };
|
|
61
40
|
throw new WebSearchApiError("MISSING_CREDENTIALS", "\u641C\u7D22\u670D\u52A1\u5C1A\u672A\u51C6\u5907\u597D\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u767B\u5F55\u58A8\u5B9D\u5E76\u5B8C\u6210\u5BA2\u6237\u7AEF\u521D\u59CB\u5316\u540E\u91CD\u8BD5\u3002");
|
|
62
41
|
}
|
|
42
|
+
function resolveSearchEndpoint(metadata) {
|
|
43
|
+
const baseUrl = nonEmptyString(record(record(metadata)?.servers)?.apiGatewayBaseUrl);
|
|
44
|
+
if (!baseUrl) {
|
|
45
|
+
throw new WebSearchApiError("INVALID_CONFIG", "\u641C\u7D22\u670D\u52A1\u5730\u5740\u5C1A\u672A\u914D\u7F6E\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u68C0\u67E5\u5BA2\u6237\u7AEF\u914D\u7F6E\u3002");
|
|
46
|
+
}
|
|
47
|
+
const base = toEndpoint(baseUrl);
|
|
48
|
+
return new URL("/apikey-manage/api/search", base);
|
|
49
|
+
}
|
|
63
50
|
function requestSignal(signal, timeoutMs) {
|
|
64
51
|
const timeout = AbortSignal.timeout(timeoutMs);
|
|
65
52
|
return signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
@@ -158,27 +145,12 @@ function toEndpoint(endpointUrl) {
|
|
|
158
145
|
}
|
|
159
146
|
var WebSearchApiClient = class {
|
|
160
147
|
config;
|
|
161
|
-
environments;
|
|
162
148
|
fetchImpl;
|
|
163
149
|
readFileImpl;
|
|
164
150
|
nowSeconds;
|
|
165
151
|
nonce;
|
|
166
152
|
constructor(config, dependencies = {}) {
|
|
167
153
|
this.config = config;
|
|
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
|
-
};
|
|
182
154
|
for (const [name2, value] of [
|
|
183
155
|
["timeoutMs", config.timeoutMs],
|
|
184
156
|
["maxResponseBytes", config.maxResponseBytes],
|
|
@@ -213,11 +185,12 @@ var WebSearchApiClient = class {
|
|
|
213
185
|
try {
|
|
214
186
|
metadata = JSON.parse(await this.readFileImpl(this.config.metadataPath, "utf8"));
|
|
215
187
|
} catch (error) {
|
|
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", {
|
|
188
|
+
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", {
|
|
189
|
+
cause: error
|
|
190
|
+
});
|
|
217
191
|
}
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
const credentials = resolveSearchCredentials(metadata, resolved.channelId, resolved.legacyChannelId);
|
|
192
|
+
const endpoint = resolveSearchEndpoint(metadata);
|
|
193
|
+
const credentials = resolveSearchCredentials(metadata);
|
|
221
194
|
const call = async (service) => {
|
|
222
195
|
const timestamp = String(this.nowSeconds());
|
|
223
196
|
const nonce = this.nonce();
|
|
@@ -246,7 +219,7 @@ ${nonce}`;
|
|
|
246
219
|
const effectiveSignal = requestSignal(signal, this.config.timeoutMs);
|
|
247
220
|
let response;
|
|
248
221
|
try {
|
|
249
|
-
response = await this.fetchImpl(
|
|
222
|
+
response = await this.fetchImpl(endpoint, {
|
|
250
223
|
method: "POST",
|
|
251
224
|
headers: { accept: "application/json", "content-type": "application/json" },
|
|
252
225
|
body: JSON.stringify(body),
|
|
@@ -260,7 +233,9 @@ ${nonce}`;
|
|
|
260
233
|
cause: error
|
|
261
234
|
});
|
|
262
235
|
}
|
|
263
|
-
throw new WebSearchApiError("NETWORK_ERROR", `\u6682\u65F6\u65E0\u6CD5\u8FDE\u63A5${searchServiceLabel(service)}\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5\u3002`, {
|
|
236
|
+
throw new WebSearchApiError("NETWORK_ERROR", `\u6682\u65F6\u65E0\u6CD5\u8FDE\u63A5 ${searchServiceLabel(service)}\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5\u3002`, {
|
|
237
|
+
cause: error
|
|
238
|
+
});
|
|
264
239
|
}
|
|
265
240
|
const text = await responseText(response, this.config.maxResponseBytes);
|
|
266
241
|
if (!response.ok) {
|
|
@@ -269,23 +244,23 @@ ${nonce}`;
|
|
|
269
244
|
return parseResponse(text, query, service);
|
|
270
245
|
};
|
|
271
246
|
try {
|
|
272
|
-
const
|
|
273
|
-
if (
|
|
274
|
-
return
|
|
247
|
+
const bocha = await call("bocha_search");
|
|
248
|
+
if (bocha.results.length > 0)
|
|
249
|
+
return bocha;
|
|
275
250
|
} catch (error) {
|
|
276
251
|
if (signal?.aborted)
|
|
277
252
|
throw error;
|
|
278
253
|
}
|
|
279
|
-
return call("
|
|
254
|
+
return call("tavily_search");
|
|
280
255
|
}
|
|
281
256
|
};
|
|
282
257
|
|
|
283
|
-
// dist
|
|
258
|
+
// dist/src/tools.js
|
|
284
259
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
285
260
|
function createWebSearchTool(search) {
|
|
286
261
|
return defineTool({
|
|
287
262
|
name: "web_search",
|
|
288
|
-
description: "Search the public web with
|
|
263
|
+
description: "Search the public web with Mobook search services. Use Bocha first and fall back to Tavily when Bocha fails or returns no results. Use this for current information, source discovery, fact verification, news, weather, prices, schedules, or any question that requires internet access. In the final answer, summarize first, then present useful sources as a numbered list with Markdown links in the form [title | siteName](url), followed by a concise snippet-based explanation. Never expose the raw JSON or internal provider fields.",
|
|
289
264
|
parameters: {
|
|
290
265
|
query: { type: "string", required: true, description: "A focused web search query." },
|
|
291
266
|
count: { type: "integer", description: "Number of results to return. Defaults to 5; maximum 20." },
|
|
@@ -313,16 +288,14 @@ function createWebSearchTool(search) {
|
|
|
313
288
|
});
|
|
314
289
|
}
|
|
315
290
|
|
|
316
|
-
// dist
|
|
291
|
+
// dist/src/index.js
|
|
317
292
|
var MBH_WEB_SEARCH_SERVICE_KEY = "mbhWebSearch";
|
|
318
293
|
|
|
319
|
-
// dist
|
|
294
|
+
// dist/plugin/index.js
|
|
320
295
|
var name = "@dcrays/web-search";
|
|
321
296
|
var inject = ["tools"];
|
|
322
297
|
var Config = z.object({
|
|
323
298
|
enabled: z.boolean().default(true),
|
|
324
|
-
endpointUrl: z.string().default(""),
|
|
325
|
-
metadataPath: z.string().default(""),
|
|
326
299
|
timeoutMs: z.natural().min(1).default(3e4),
|
|
327
300
|
maxResponseBytes: z.natural().min(1).default(1024 * 1024),
|
|
328
301
|
defaultCount: z.natural().min(1).default(5),
|
|
@@ -337,8 +310,7 @@ var MbhWebSearchService = class extends Service {
|
|
|
337
310
|
if (!config.enabled)
|
|
338
311
|
return;
|
|
339
312
|
this.operations = new WebSearchApiClient({
|
|
340
|
-
metadataPath: resolveMetadataPath(
|
|
341
|
-
...config.endpointUrl.trim() ? { endpointOverride: config.endpointUrl.trim() } : {},
|
|
313
|
+
metadataPath: resolveMetadataPath(),
|
|
342
314
|
timeoutMs: config.timeoutMs,
|
|
343
315
|
maxResponseBytes: config.maxResponseBytes,
|
|
344
316
|
defaultCount: config.defaultCount,
|
|
@@ -355,8 +327,8 @@ var MbhWebSearchService = class extends Service {
|
|
|
355
327
|
return this.operations.search(request, signal);
|
|
356
328
|
}
|
|
357
329
|
};
|
|
358
|
-
function resolveMetadataPath(
|
|
359
|
-
return
|
|
330
|
+
function resolveMetadataPath() {
|
|
331
|
+
return resolve(resolveDshHome(), "mobook.json");
|
|
360
332
|
}
|
|
361
333
|
function apply(ctx, config) {
|
|
362
334
|
const service = new MbhWebSearchService(ctx, config);
|
package/src/api-client.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type EnvConfig, type WebSearchEnvironment } from './config/env-config.js';
|
|
2
1
|
export interface WebSearchRequest {
|
|
3
2
|
query: string;
|
|
4
3
|
count?: number;
|
|
@@ -26,8 +25,6 @@ export interface WebSearchOperations {
|
|
|
26
25
|
}
|
|
27
26
|
export interface WebSearchApiClientConfig {
|
|
28
27
|
metadataPath: string;
|
|
29
|
-
endpointOverride?: string;
|
|
30
|
-
environments?: Record<WebSearchEnvironment, EnvConfig>;
|
|
31
28
|
timeoutMs: number;
|
|
32
29
|
maxResponseBytes: number;
|
|
33
30
|
defaultCount: number;
|
|
@@ -50,10 +47,10 @@ interface SearchCredentials {
|
|
|
50
47
|
botToken: string;
|
|
51
48
|
deviceId: string;
|
|
52
49
|
}
|
|
53
|
-
export declare function resolveSearchCredentials(metadata: unknown
|
|
50
|
+
export declare function resolveSearchCredentials(metadata: unknown): SearchCredentials;
|
|
51
|
+
export declare function resolveSearchEndpoint(metadata: unknown): URL;
|
|
54
52
|
export declare class WebSearchApiClient implements WebSearchOperations {
|
|
55
53
|
private readonly config;
|
|
56
|
-
private readonly environments;
|
|
57
54
|
private readonly fetchImpl;
|
|
58
55
|
private readonly readFileImpl;
|
|
59
56
|
private readonly nowSeconds;
|
package/src/api-client.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
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';
|
|
4
3
|
export class WebSearchApiError extends Error {
|
|
5
4
|
code;
|
|
6
5
|
constructor(code, message, options) {
|
|
@@ -19,20 +18,26 @@ function record(value) {
|
|
|
19
18
|
function nonEmptyString(value) {
|
|
20
19
|
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
21
20
|
}
|
|
22
|
-
export function resolveSearchCredentials(metadata
|
|
21
|
+
export function resolveSearchCredentials(metadata) {
|
|
23
22
|
const root = record(metadata);
|
|
24
|
-
const plugins = record(root?.plugins);
|
|
25
23
|
const hardware = record(root?.hardware);
|
|
24
|
+
const account = record(root?.account);
|
|
26
25
|
const deviceId = nonEmptyString(hardware?.fingerprint);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return { userId, botToken, deviceId };
|
|
33
|
-
}
|
|
26
|
+
const userIdValue = account?.userId;
|
|
27
|
+
const userId = typeof userIdValue === 'number' && Number.isSafeInteger(userIdValue) ? String(userIdValue) : nonEmptyString(userIdValue);
|
|
28
|
+
const botToken = nonEmptyString(account?.botToken);
|
|
29
|
+
if (userId && botToken && deviceId)
|
|
30
|
+
return { userId, botToken, deviceId };
|
|
34
31
|
throw new WebSearchApiError('MISSING_CREDENTIALS', '搜索服务尚未准备好,请确认已登录墨宝并完成客户端初始化后重试。');
|
|
35
32
|
}
|
|
33
|
+
export function resolveSearchEndpoint(metadata) {
|
|
34
|
+
const baseUrl = nonEmptyString(record(record(metadata)?.servers)?.apiGatewayBaseUrl);
|
|
35
|
+
if (!baseUrl) {
|
|
36
|
+
throw new WebSearchApiError('INVALID_CONFIG', '搜索服务地址尚未配置,请联系管理员检查客户端配置。');
|
|
37
|
+
}
|
|
38
|
+
const base = toEndpoint(baseUrl);
|
|
39
|
+
return new URL('/apikey-manage/api/search', base);
|
|
40
|
+
}
|
|
36
41
|
function requestSignal(signal, timeoutMs) {
|
|
37
42
|
const timeout = AbortSignal.timeout(timeoutMs);
|
|
38
43
|
return signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
@@ -134,27 +139,12 @@ function toEndpoint(endpointUrl) {
|
|
|
134
139
|
}
|
|
135
140
|
export class WebSearchApiClient {
|
|
136
141
|
config;
|
|
137
|
-
environments;
|
|
138
142
|
fetchImpl;
|
|
139
143
|
readFileImpl;
|
|
140
144
|
nowSeconds;
|
|
141
145
|
nonce;
|
|
142
146
|
constructor(config, dependencies = {}) {
|
|
143
147
|
this.config = config;
|
|
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
|
-
};
|
|
158
148
|
for (const [name, value] of [
|
|
159
149
|
['timeoutMs', config.timeoutMs],
|
|
160
150
|
['maxResponseBytes', config.maxResponseBytes],
|
|
@@ -190,11 +180,12 @@ export class WebSearchApiClient {
|
|
|
190
180
|
metadata = JSON.parse(await this.readFileImpl(this.config.metadataPath, 'utf8'));
|
|
191
181
|
}
|
|
192
182
|
catch (error) {
|
|
193
|
-
throw new WebSearchApiError('MISSING_CREDENTIALS', '暂时无法读取墨宝运行配置,请确认客户端已正常初始化后重试。', {
|
|
183
|
+
throw new WebSearchApiError('MISSING_CREDENTIALS', '暂时无法读取墨宝运行配置,请确认客户端已正常初始化后重试。', {
|
|
184
|
+
cause: error
|
|
185
|
+
});
|
|
194
186
|
}
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
const credentials = resolveSearchCredentials(metadata, resolved.channelId, resolved.legacyChannelId);
|
|
187
|
+
const endpoint = resolveSearchEndpoint(metadata);
|
|
188
|
+
const credentials = resolveSearchCredentials(metadata);
|
|
198
189
|
const call = async (service) => {
|
|
199
190
|
const timestamp = String(this.nowSeconds());
|
|
200
191
|
const nonce = this.nonce();
|
|
@@ -220,7 +211,7 @@ export class WebSearchApiClient {
|
|
|
220
211
|
const effectiveSignal = requestSignal(signal, this.config.timeoutMs);
|
|
221
212
|
let response;
|
|
222
213
|
try {
|
|
223
|
-
response = await this.fetchImpl(
|
|
214
|
+
response = await this.fetchImpl(endpoint, {
|
|
224
215
|
method: 'POST',
|
|
225
216
|
headers: { accept: 'application/json', 'content-type': 'application/json' },
|
|
226
217
|
body: JSON.stringify(body),
|
|
@@ -235,7 +226,9 @@ export class WebSearchApiClient {
|
|
|
235
226
|
cause: error
|
|
236
227
|
});
|
|
237
228
|
}
|
|
238
|
-
throw new WebSearchApiError('NETWORK_ERROR',
|
|
229
|
+
throw new WebSearchApiError('NETWORK_ERROR', `暂时无法连接 ${searchServiceLabel(service)},请检查网络后重试。`, {
|
|
230
|
+
cause: error
|
|
231
|
+
});
|
|
239
232
|
}
|
|
240
233
|
const text = await responseText(response, this.config.maxResponseBytes);
|
|
241
234
|
if (!response.ok) {
|
|
@@ -244,14 +237,14 @@ export class WebSearchApiClient {
|
|
|
244
237
|
return parseResponse(text, query, service);
|
|
245
238
|
};
|
|
246
239
|
try {
|
|
247
|
-
const
|
|
248
|
-
if (
|
|
249
|
-
return
|
|
240
|
+
const bocha = await call('bocha_search');
|
|
241
|
+
if (bocha.results.length > 0)
|
|
242
|
+
return bocha;
|
|
250
243
|
}
|
|
251
244
|
catch (error) {
|
|
252
245
|
if (signal?.aborted)
|
|
253
246
|
throw error;
|
|
254
247
|
}
|
|
255
|
-
return call('
|
|
248
|
+
return call('tavily_search');
|
|
256
249
|
}
|
|
257
250
|
}
|
|
@@ -1,15 +1 @@
|
|
|
1
|
-
export type WebSearchEnvironment = 'production' | 'test';
|
|
2
|
-
export interface EnvConfig {
|
|
3
|
-
channelId: string;
|
|
4
|
-
legacyChannelId: string;
|
|
5
|
-
endpointUrl: string;
|
|
6
|
-
}
|
|
7
1
|
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,22 +1 @@
|
|
|
1
1
|
export const PACKAGE_NAME = '@dcrays/web-search';
|
|
2
|
-
export const ENV_CONFIG = {
|
|
3
|
-
production: {
|
|
4
|
-
channelId: 'mbh-chat',
|
|
5
|
-
legacyChannelId: 'mbhchat',
|
|
6
|
-
endpointUrl: 'https://api-gateway.shuwenda.com/apikey-manage/api/search'
|
|
7
|
-
},
|
|
8
|
-
test: {
|
|
9
|
-
channelId: 'mbh-chat-test',
|
|
10
|
-
legacyChannelId: 'mbhchat-test',
|
|
11
|
-
endpointUrl: 'https://api-gateway.shuwenda.icu/apikey-manage/api/search'
|
|
12
|
-
}
|
|
13
|
-
};
|
|
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
|
-
}
|
package/src/tools.js
CHANGED
|
@@ -2,7 +2,7 @@ import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
|
2
2
|
export function createWebSearchTool(search) {
|
|
3
3
|
return defineTool({
|
|
4
4
|
name: 'web_search',
|
|
5
|
-
description: 'Search the public web with
|
|
5
|
+
description: 'Search the public web with Mobook search services. Use Bocha first and fall back to Tavily when Bocha fails or returns no results. Use this for current information, source discovery, fact verification, news, weather, prices, schedules, or any question that requires internet access. In the final answer, summarize first, then present useful sources as a numbered list with Markdown links in the form [title | siteName](url), followed by a concise snippet-based explanation. Never expose the raw JSON or internal provider fields.',
|
|
6
6
|
parameters: {
|
|
7
7
|
query: { type: 'string', required: true, description: 'A focused web search query.' },
|
|
8
8
|
count: { type: 'integer', description: 'Number of results to return. Defaults to 5; maximum 20.' },
|