dsh-free-search 0.6.5 → 0.6.6

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/lib/client.js CHANGED
@@ -290,7 +290,7 @@ window.__ModuleLoader__.load({
290
290
  };
291
291
  const tt = (lang) => I18N[lang === "en" ? "en" : "zh"];
292
292
  // 当前插件版本(与 lib/index.js 的 PLUGIN_VERSION 保持一致)
293
- const PLUGIN_VERSION = "0.6.5";
293
+ const PLUGIN_VERSION = "0.6.6";
294
294
  const ENGINES = [
295
295
  { id: "auto", label: "Auto · 智能路由", badge: "AUTO", link: null },
296
296
  { id: "multi", label: "Multi Search · 多引擎", badge: "MULTI", link: null },
@@ -647,7 +647,7 @@ window.__ModuleLoader__.load({
647
647
  setTestResult({
648
648
  ok: true,
649
649
  count: sources.length,
650
- engine: result.value.provider ?? provider,
650
+ engine: result.value.provider === "multi_search" ? "multi" : (result.value.provider ?? provider),
651
651
  content: result.value.content ?? "",
652
652
  sample: sources[0]?.title ?? "",
653
653
  });
package/lib/index.js CHANGED
@@ -61,6 +61,9 @@ const ALL_ENGINES = ["ddg", "ddg-lite", "bing", "searxng", "anysearch", "exa", "
61
61
  // 支持 time_range 过滤的引擎
62
62
  const TIME_ENGINES = ["tavily", "exa", "keenable", "firecrawl", "parallel", "searxng", "ddg", "ddg-lite", "baidu", "doubao"];
63
63
 
64
+ // 虚拟搜索模式:不是单个引擎,而是 provider.search 内部的路由/并发策略
65
+ const SEARCH_MODES = ["auto", "multi"];
66
+
64
67
  const DEFAULT_FALLBACK_ORDER = ["exa", "tavily", "keenable", "firecrawl", "parallel", "perplexity", "serpbase", "deepseek-official", "you", "baidu", "kimi", "aliyun", "doubao", "bing", "anysearch", "ddg", "ddg-lite", "searxng"];
65
68
 
66
69
  function normalizeDisabledEngines(value) {
@@ -118,7 +121,7 @@ function routeEngines(query, { timeRange, disabledEngines = [], fallbackOrder =
118
121
  }
119
122
 
120
123
  // 当前插件版本(发布时与 package.json 同步)
121
- const PLUGIN_VERSION = "0.6.5";
124
+ const PLUGIN_VERSION = "0.6.6";
122
125
  // 检查更新的 npm registry 元数据地址(dsh-free-search 是 npmjs 上的公开包)
123
126
  const NPM_REGISTRY_URL = "https://registry.npmjs.org/dsh-free-search/latest";
124
127
  const PLUGIN_NPM_URL = "https://www.npmjs.com/package/dsh-free-search";
@@ -2036,8 +2039,11 @@ function makeBridgeRoutes(settings, search, testEngine, getCredentials) {
2036
2039
  }
2037
2040
  const maxResults = Math.min(Math.max(Number(request.maxResults) || 5, 1), 10);
2038
2041
  const timeRange = parseTimeRange(request.timeRange);
2039
- // 指定 engine:直测该引擎本身(不走回退链),报告它自己的可用性
2040
- if (typeof request.engine === "string" && request.engine.length > 0) {
2042
+ // 指定 engine:直测该引擎本身(不走回退链),报告它自己的可用性。
2043
+ // auto / multi 是虚拟模式,没有"单引擎本身"可测 → 交给下面的 provider.search,
2044
+ // 真实跑一遍路由/并发链路(否则设置页「测试引擎」会对它们报 unknown engine)。
2045
+ const engineIsMode = typeof request.engine === "string" && SEARCH_MODES.includes(request.engine);
2046
+ if (typeof request.engine === "string" && request.engine.length > 0 && !engineIsMode) {
2041
2047
  if (typeof testEngine !== "function") {
2042
2048
  return { ok: false, code: "search-unavailable", message: "engine test is not wired" };
2043
2049
  }
@@ -3056,7 +3062,7 @@ function apply(ctx, config) {
3056
3062
  parameters: {
3057
3063
  engines: {
3058
3064
  type: "array",
3059
- description: "Which engines to test (default: all). Options: ddg, ddg-lite, bing, searxng, anysearch, exa, tavily, keenable, firecrawl, parallel, perplexity, serpbase, deepseek-official, you, baidu, kimi, aliyun, doubao.",
3065
+ description: "Which engines to test (default: all enabled engines). Options: ddg, ddg-lite, bing, searxng, anysearch, exa, tavily, keenable, firecrawl, parallel, perplexity, serpbase, deepseek-official, you, baidu, kimi, aliyun, doubao; the virtual modes auto and multi are also accepted and run the real routing/concurrent path.",
3060
3066
  items: { type: "string" },
3061
3067
  },
3062
3068
  query: {
@@ -3089,7 +3095,8 @@ function apply(ctx, config) {
3089
3095
  render(args, value) {
3090
3096
  const lines = value.results.map((r) => {
3091
3097
  if (r.status === "ok") {
3092
- return `- ${r.engine}: OK (${r.results} results${r.sampleTitle ? `, e.g. "${r.sampleTitle.slice(0, 40)}"` : ""})`;
3098
+ const via = r.engineUsed && r.engineUsed !== r.engine ? ` via ${r.engineUsed}` : "";
3099
+ return `- ${r.engine}: OK (${r.results} results${via}${r.sampleTitle ? `, e.g. "${r.sampleTitle.slice(0, 40)}"` : ""})`;
3093
3100
  }
3094
3101
  if (r.status === "disabled") return `- ${r.engine}: DISABLED`;
3095
3102
  return `- ${r.engine}: FAIL - ${r.error}`;
@@ -3103,7 +3110,7 @@ function apply(ctx, config) {
3103
3110
  const disabled = new Set(normalizeDisabledEngines(current().disabledEngines));
3104
3111
  const explicit = Array.isArray(args.engines) && args.engines.length > 0;
3105
3112
  const engines = explicit
3106
- ? args.engines.filter((engine) => ALL_ENGINES.includes(engine))
3113
+ ? args.engines.filter((engine) => ALL_ENGINES.includes(engine) || SEARCH_MODES.includes(engine))
3107
3114
  : enabledEngines(current().disabledEngines, current().fallbackOrder);
3108
3115
  const results = [];
3109
3116
  for (const engine of engines) {
@@ -3111,6 +3118,25 @@ function apply(ctx, config) {
3111
3118
  results.push({ engine, status: "disabled" });
3112
3119
  continue;
3113
3120
  }
3121
+ // 虚拟模式(auto/multi):走 provider.search 真实路由/并发,报告实际生效的引擎
3122
+ if (SEARCH_MODES.includes(engine)) {
3123
+ try {
3124
+ const r = await provider.search({ query: args.query, maxResults: 2, engine });
3125
+ const sources = r.sources ?? [];
3126
+ if (sources.length === 0) {
3127
+ results.push({ engine, status: "fail", error: "0 results" });
3128
+ } else {
3129
+ const item = { engine, status: "ok", results: sources.length, engineUsed: r.provider ?? r.engine ?? engine };
3130
+ if (sources[0]?.title) item.sampleTitle = String(sources[0].title);
3131
+ if (sources[0]?.url) item.sampleUrl = String(sources[0].url);
3132
+ if (r.content) item.note = String(r.content);
3133
+ results.push(item);
3134
+ }
3135
+ } catch (error) {
3136
+ results.push({ engine, status: "fail", error: error instanceof Error ? error.message : String(error) });
3137
+ }
3138
+ continue;
3139
+ }
3114
3140
  const r = await runEngineTest(engine, args.query);
3115
3141
  if (r.ok) {
3116
3142
  const item = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-free-search",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "Free web search for DeepSeek Harness: 18 engines (Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable/Firecrawl/Parallel keyless; Perplexity/SerpBase/DeepSeek/You.com/Baidu/Kimi/Aliyun/Doubao with key) + auto smart routing + global engine enable/disable & fallback priority + multi mode (parallel top-3 merge) + multi_search cross-source tool + time filtering + platform search + web_fetch, with web settings UI.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",