@darlingc/dsh-freesearch 0.5.5 → 0.5.7

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 CHANGED
@@ -9,8 +9,8 @@
9
9
  ## 中文
10
10
 
11
11
  <div align="center">
12
- <a href="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-free1.png">
13
- <img src="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-free1.png" alt="免费引擎设置 (Bing)" width="820" />
12
+ <a href="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-free1.png">
13
+ <img src="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-free1.png" alt="免费引擎设置 (Bing)" width="820" />
14
14
  </a>
15
15
  <br>
16
16
  <sub>▲ 免费引擎(以Bing为例)</sub>
@@ -36,7 +36,7 @@ dsh 默认的搜索 provider 依赖 DeepSeek 官方 API key(`DEEPSEEK_API_KEY`
36
36
  - **统一引擎回退** —— 任何引擎失败(付费/免费,缺 key/401/限流/网络)自动轮流尝试下一个引擎:首选引擎 → 其他引擎(exa/tavily/keenable 无 key 也会尝试,因为它们自带 keyless 免费额度)→ 剩余免费引擎,搜索永不直接失败;结果顶部注明实际生效的引擎(如 `Note: perplexity unavailable or failed, using exa.`)
37
37
  - **时间过滤** —— `advanced_search` 工具支持 `timeRange`:固定档、自定义相对值、绝对日期三种形式(详见下方逻辑说明)
38
38
  - **系统提示词注入** —— agent 知道当前用哪个引擎、哪些需要 key
39
- - **版本号 + 检查更新** —— 设置卡片显示当前版本(v0.5.5),"检查更新"按钮直连 npm registry 对比最新版,有新版本时提示并可一键跳转
39
+ - **版本号 + 检查更新** —— 设置卡片显示当前版本(v0.5.6),"检查更新"按钮直连 npm registry 对比最新版,有新版本时提示并可一键跳转
40
40
  - **结果缓存** —— 相同查询(含引擎/时间过滤参数)5 分钟内命中缓存(LRU 50 条),防免费引擎限流、省付费额度;时长可在设置页 0-5 分钟自由配置(0 关闭)
41
41
  - **免费标注** —— 设置页中免费引擎带绿色 `FREE` 徽章,付费引擎带橙色 `API KEY` 徽章
42
42
  - **网页抓取(web_fetch)** —— 让 agent 抓取网页内容(官方 `dsh-web-fetch-http` provider,纯 JS,零额外依赖)
@@ -81,8 +81,8 @@ dsh 默认的搜索 provider 依赖 DeepSeek 官方 API key(`DEEPSEEK_API_KEY`
81
81
  - **Key 配置**:在 AI Studio(aistudio.google.com/apikey)免费创建 `GEMINI_API_KEY`,放入 `~/.dsh/.credentials.yaml` 的 `refs.GEMINI_API_KEY`,或在 `~/.dsh/settings.yaml` 的 `free-search:` 下设置 `geminiApiKey`。
82
82
  - **模型**:默认 `gemini-2.5-flash`(免费层唯一已实测可联网的模型)。当前 AI Studio 免费层**无需绑卡**即可用 Google Search grounding。
83
83
  - **⚠️ 配额警示(务必注意)**:
84
- - `gemini-2.5-flash` **文本输出 RPD 仅约 20/天** —— 千万别把它当常规文本问答模型用,会秒爆。本引擎只走 grounding(联网搜索),计的是**搜索 RPD**,不占那 20 次文本额度。
85
- - **搜索 RPD 约 1,500/天**(与 Flash-Lite 共享),**RPM 约 5**。每次搜索引擎调用 = 1 次 grounded prompt = 1 搜索 RPD。超限会返回 HTTP 429,本插件会**自动回退到其它免费引擎**(Bing 等),搜索不会因此失败。
84
+ - `gemini-2.5-flash` **文本输出 RPD 仅约 20/天** —— 千万别把它当常规文本问答模型用,会秒爆。⚠️ **每次发起 grounded 搜索请求,模型生成过程会同时扣 1 次文本输出额度 + 1 次搜索接地额度**:因此那 **20 次文本输出 RPD 就是实际瓶颈**,即便搜索 RPD 高达约 1,500/天,实际每天都只能发起约 **20 次** grounded 搜索。
85
+ - **搜索 RPD 约 1,500/天**(与 Flash-Lite 共享),**RPM 约 5**。每次搜索引擎调用 = 1 次 grounded prompt = **同时耗 1 文本 + 1 搜索额度**。超限会返回 HTTP 429,本插件会**自动回退到其它免费引擎**(Bing 等),搜索不会因此失败。
86
86
  - 因此**不建议把 `gemini` 设为默认首选引擎**(`free-search.provider: gemini`),默认 `bing` + 失败自动回退即可;把 `gemini` 当按需/回退引擎最稳。
87
87
  - **与其它引擎差异**:Gemini grounding 返回的是"模型 Ground 到的来源集合",不是像 Bing 那样的排序结果列表——数量不固定、通常偏少、无优先级;`maxResults` 只能做客户端截断。作为默认搜索体验与真实搜索引擎略有不同。
88
88
 
@@ -162,15 +162,15 @@ dsh plugin --profile web add @darlingc/dsh-freesearch --registry=https://npm.pkg
162
162
  <table align="center" style="border: none; border-collapse: collapse;">
163
163
  <tr style="border: none;">
164
164
  <td align="center" width="50%" style="border: none; padding: 6px;">
165
- <a href="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-free.png">
166
- <img src="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-free.png" alt="免费引擎设置" width="100%" />
165
+ <a href="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-free.png">
166
+ <img src="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-free.png" alt="免费引擎设置" width="100%" />
167
167
  </a>
168
168
  <br>
169
169
  <sub>▲ <b>免费引擎</b>(显示绿色 FREE 徽章与官网链接)</sub>
170
170
  </td>
171
171
  <td align="center" width="50%" style="border: none; padding: 6px;">
172
- <a href="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-apikey.png">
173
- <img src="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-apikey.png" alt="付费引擎设置" width="100%" />
172
+ <a href="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-apikey.png">
173
+ <img src="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-apikey.png" alt="付费引擎设置" width="100%" />
174
174
  </a>
175
175
  <br>
176
176
  <sub>▲ <b>付费/API Key 引擎</b>(显示橙色 API KEY 徽章与获取链接)</sub>
@@ -268,17 +268,6 @@ Search engine test:
268
268
 
269
269
  全部走公开 API,零外部依赖、无需任何 key,开箱即用。
270
270
 
271
- ### 本地引擎切换工具(tools/)
272
-
273
- `tools/` 目录附带了一个本地切换小工具(零依赖):
274
-
275
- - **`启动搜索引擎切换器.cmd`**(Windows)——双击启动本地 Node 服务(`http://127.0.0.1:4789`)并自动打开浏览器选择页面
276
- - **`switch-engine.html`** —— 选择页面:显示当前引擎,点选新引擎,一键写入配置
277
- - **`server.mjs`** —— 本地服务,负责读写 `~/.dsh/profiles/web/cordis.patch.yml`
278
- - **`switch-engine.ps1`** —— 无界面命令行版:`powershell -File tools/switch-engine.ps1 -Engine bing`
279
-
280
- 切换后重启 `dsh web` 生效。
281
-
282
271
  > 配置卡片挂在官方设置页的 `settings.plugin.item` 插槽(dsh 自带),配置读写走插件自建 bridge,**不依赖 dsh-web-ui**,插件可独立使用。
283
272
 
284
273
  ### 代理说明(国内用户)
@@ -304,8 +293,8 @@ Windows 用户:桌面快捷方式已内置此配置(`set NODE_USE_ENV_PROXY=
304
293
  ## English
305
294
 
306
295
  <div align="center">
307
- <a href="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-free1.png">
308
- <img src="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-free1.png" alt="Free Engine Settings (Bing)" width="820" />
296
+ <a href="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-free1.png">
297
+ <img src="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-free1.png" alt="Free Engine Settings (Bing)" width="820" />
309
298
  </a>
310
299
  <br>
311
300
  <sub>▲ Free engine (using Bing as an example)</sub>
@@ -331,7 +320,7 @@ This plugin provides multiple free search engines with automatic fallback, compl
331
320
  - **Unified Engine Fallback** — Any engine failure (paid or free, missing key, 401, rate limit, network error) automatically tries the next engine: the configured engine first, then other engines (exa/tavily/keenable are tried even without a key because they have built-in keyless quota), then the remaining free engines (Bing/AnySearch etc.) — with a note attached to the results naming the engine that actually served them (e.g. `Note: perplexity unavailable or failed, using exa.`). Search never fails outright.
332
321
  - **Time Filtering** — The `advanced_search` tool supports `timeRange`: fixed tiers, custom relative values, or an absolute date (details below)
333
322
  - **System Prompt Injection** — The agent is aware of the currently active engine and which engines require API keys
334
- - **Version + Update Check** — The settings card shows the current version (v0.5.5), and a "Check update" button queries the npm registry to compare against the latest release, prompting a one-click jump when a newer version exists
323
+ - **Version + Update Check** — The settings card shows the current version (v0.5.6), and a "Check update" button queries the npm registry to compare against the latest release, prompting a one-click jump when a newer version exists
335
324
  - **Result Caching** — Identical queries (same engine / time-filter args) hit an LRU cache (50 entries) for up to 5 minutes, protecting free engines from rate-limiting and saving paid quota; the TTL is configurable from 0-5 minutes in the settings UI (0 disables caching)
336
325
  - **Visual Badges** — Free engines feature a green `FREE` badge, while paid engines show an orange `API KEY` badge in the settings UI
337
326
  - **Webpage Fetching (`web_fetch`)** — Allows the agent to read full webpage contents (official `dsh-web-fetch-http` provider, pure JS, zero extra dependencies)
@@ -376,8 +365,8 @@ This plugin provides multiple free search engines with automatic fallback, compl
376
365
  - **Key**: create a free `GEMINI_API_KEY` at AI Studio (aistudio.google.com/apikey) and store it in `refs.GEMINI_API_KEY` under `~/.dsh/.credentials.yaml`, or set `geminiApiKey` under `free-search:` in `~/.dsh/settings.yaml`.
377
366
  - **Model**: defaults to `gemini-2.5-flash` (the only free-tier model verified to work online here). Google Search Grounding is available on the AI Studio **free tier with no credit card**.
378
367
  - **⚠️ Quota warning (important)**:
379
- - `gemini-2.5-flash` has a **text-output RPD of only ~20/day** — do **not** use it as a general text model or you will exhaust it instantly. This engine only uses grounding (web search), which counts against the **search RPD**, not the text quota.
380
- - **Search RPD ≈ 1,500/day** (shared with Flash-Lite), **RPM ≈ 5**. Each engine call = 1 grounded prompt = 1 search RPD. Exceeding it returns HTTP 429, and this plugin **auto-falls-back to other free engines** (Bing, etc.), so search never hard-fails.
368
+ - `gemini-2.5-flash` has a **text-output RPD of only ~20/day** — do **not** use it as a general text model or you will exhaust it instantly. ⚠️ **Each grounded search request consumes 1 text-output quota + 1 search-grounding quota simultaneously during generation**, so the **~20/day text-output RPD is the real bottleneck**: even though the search RPD is ~1,500/day, you can effectively make only about **20 grounded searches per day**.
369
+ - **Search RPD ≈ 1,500/day** (shared with Flash-Lite), **RPM ≈ 5**. Each engine call = 1 grounded prompt = **consumes 1 text + 1 search quota at once**. Exceeding it returns HTTP 429, and this plugin **auto-falls-back to other free engines** (Bing, etc.), so search never hard-fails.
381
370
  - So keep `provider: bing` as default and let `gemini` act as a fallback / on-demand engine rather than the primary load.
382
371
  - **Difference vs. other engines**: Gemini grounding returns the set of sources the model grounded on — not a ranked SERP list like Bing/DDG. Count is not fixed and is usually small, with no ordering; `maxResults` can only truncate client-side.
383
372
 
@@ -424,15 +413,15 @@ After installation, navigate to **Settings → Plugins → Configurable** tab
424
413
  <table align="center" style="border: none; border-collapse: collapse;">
425
414
  <tr style="border: none;">
426
415
  <td align="center" width="50%" style="border: none; padding: 6px;">
427
- <a href="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-free.png">
428
- <img src="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-free.png" alt="Free Engine Settings" width="100%" />
416
+ <a href="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-free.png">
417
+ <img src="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-free.png" alt="Free Engine Settings" width="100%" />
429
418
  </a>
430
419
  <br>
431
420
  <sub>▲ <b>Free Engine</b> (shows green FREE badge and official website link)</sub>
432
421
  </td>
433
422
  <td align="center" width="50%" style="border: none; padding: 6px;">
434
- <a href="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-apikey.png">
435
- <img src="https://raw.githubusercontent.com/DDDMUC/dsh-free-search/master/assets/settings-apikey.png" alt="Paid/API Key Engine Settings" width="100%" />
423
+ <a href="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-apikey.png">
424
+ <img src="https://raw.githubusercontent.com/DarlingC/dsh-freesearch/master/assets/settings-apikey.png" alt="Paid/API Key Engine Settings" width="100%" />
436
425
  </a>
437
426
  <br>
438
427
  <sub>▲ <b>Paid / API Key Engine</b> (shows orange API KEY badge and link to get an API key)</sub>
@@ -530,17 +519,6 @@ Ask the agent to search specific platforms (e.g., *"Search GitHub for deepseek h
530
519
 
531
520
  All platform searches rely on public endpoints with zero external dependencies and no API keys — they work out of the box.
532
521
 
533
- ### Local Engine Switcher (`tools/`)
534
-
535
- The `tools/` directory includes a lightweight, zero-dependency switcher:
536
-
537
- - **`启动搜索引擎切换器.cmd`** (Windows) — Double-click to launch a local Node server (`http://127.0.0.1:4789`) and automatically open the engine selector page in your browser.
538
- - **`switch-engine.html`** — The selector UI: displays current engine status and allows one-click switching.
539
- - **`server.mjs`** — The local backend service responsible for reading/writing `~/.dsh/profiles/web/cordis.patch.yml`.
540
- - **`switch-engine.ps1`** — Headless PowerShell script: `powershell -File tools/switch-engine.ps1 -Engine bing`.
541
-
542
- Restart `dsh web` after switching to apply changes.
543
-
544
522
  > The settings card mounts into the official `settings.plugin.item` slot (built into DSH), and configuration reads/writes go through the plugin's own bridge. **No `dsh-web-ui` dependency — the plugin can be used standalone.**
545
523
 
546
524
  ### Proxy Note (for Users in Mainland China)
package/lib/client.js CHANGED
@@ -74,6 +74,8 @@ window.__ModuleLoader__.load({
74
74
  }
75
75
  //#endregion
76
76
 
77
+ // bridge 路径副本,必须与 lib/index.js 的 BRIDGE_PREFIX(单一权威)保持一致。
78
+ // 客户端是独立浏览器 bundle,无法 import 服务端文件,只能各放一份;改动任一方需同步另一方。
77
79
  const BRIDGE_PREFIX = "/api/dsh-free-search-settings";
78
80
  const NS = "free-search";
79
81
  const I18N = {
@@ -174,7 +176,7 @@ window.__ModuleLoader__.load({
174
176
  };
175
177
  const tt = (lang) => I18N[lang === "en" ? "en" : "zh"];
176
178
  // 当前插件版本(与 lib/index.js 的 PLUGIN_VERSION、package.json 保持一致)
177
- const PLUGIN_VERSION = "0.5.5";
179
+ const PLUGIN_VERSION = "0.5.7";
178
180
  const ENGINES = [
179
181
  { id: "ddg", label: "DuckDuckGo · HTML", badge: "FREE", link: "https://duckduckgo.com" },
180
182
  { id: "ddg-lite", label: "DuckDuckGo · Lite", badge: "FREE", link: "https://duckduckgo.com" },
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { SettingsConflictError, installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
1
+ import { SettingsConflictError } from "@deepseek-ai/dsh-settings";
2
2
  import { defineTool } from "@deepseek-ai/dsh-tools";
3
3
  import z from "@deepseek-ai/schemastery";
4
4
  import fs from "node:fs";
@@ -15,9 +15,15 @@ const USER_AGENT =
15
15
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36";
16
16
  const ACCEPT_LANG = "zh-CN,zh;q=0.9,en;q=0.8";
17
17
 
18
- const FREE_SEARCH_NS = settingsNamespace("free-search");
18
+ const FREE_SEARCH_NS = "free-search";
19
+ // bridge 路径的【单一权威】定义(M1)。
20
+ // client.js 为独立浏览器 bundle,无法 import 本文件,故在其中保留一份同步副本(同名常量);
21
+ // 改动本路径时,必须同步改 lib/client.js 的 BRIDGE_PREFIX,否则两端桥接会断。
19
22
  const BRIDGE_PREFIX = "/api/dsh-free-search-settings";
20
- const FREE_ENGINES = ["ddg", "ddg-lite", "bing", "searxng", "anysearch"];
23
+ // 免费引擎清单(导出为公共 API)。顺序必须与 search() 内部回退链 freeEngines 一致
24
+ // (见下方 search() 中 const freeEngines = [...]):bing 排最前(最稳的默认回退),
25
+ // 其余按回退优先级排列;改动此处需同步改 freeEngines,否则导出顺序会误导维护者。
26
+ const FREE_ENGINES = ["bing", "anysearch", "ddg", "ddg-lite", "searxng"];
21
27
  const ALL_ENGINES = ["ddg", "ddg-lite", "bing", "searxng", "anysearch", "exa", "tavily", "keenable", "perplexity", "deepseek-official", "gemini"];
22
28
 
23
29
  // Gemini (Google search grounding) 引擎。
@@ -28,7 +34,7 @@ const GEMINI_MODEL = "gemini-2.5-flash";
28
34
  const GEMINI_URL = `https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent`;
29
35
 
30
36
  // 当前插件版本(发布时与 package.json 同步)
31
- const PLUGIN_VERSION = "0.5.5";
37
+ const PLUGIN_VERSION = "0.5.7";
32
38
  // 检查更新的 npm registry 元数据地址(@darlingc/dsh-freesearch 是 npmjs 上的公开包)
33
39
  const NPM_REGISTRY_URL = "https://registry.npmjs.org/@darlingc%2Fdsh-freesearch/latest";
34
40
  const PLUGIN_NPM_URL = "https://www.npmjs.com/package/@darlingc/dsh-freesearch";
@@ -1324,7 +1330,7 @@ function makeBridgeRoutes(settings, search, testEngine, getCredentials) {
1324
1330
  }
1325
1331
  const expectedRevision = typeof body.expectedRevision === "number" ? body.expectedRevision : undefined;
1326
1332
  try {
1327
- await settings.mutate(settingsNamespace(ns), body.ops, expectedRevision);
1333
+ await settings.mutate(ns, body.ops, expectedRevision);
1328
1334
  } catch (error) {
1329
1335
  if (error instanceof SettingsConflictError) {
1330
1336
  return { ok: false, code: "settings-conflict", message: error.message };
@@ -1733,14 +1739,16 @@ function apply(ctx, config) {
1733
1739
  },
1734
1740
  };
1735
1741
 
1736
- installSettingsSection(ctx, FREE_SEARCH_NS, Config, config ?? {}, {
1737
- setSource: (source) => {
1738
- current = source;
1739
- },
1740
- onChange: () => {
1741
- // settings 变更时刷新系统提示词(显示最新引擎)
1742
- if (typeof refreshPrompt === "function") refreshPrompt();
1743
- },
1742
+ ctx.inject(["settings"], (settingsCtx) => {
1743
+ settingsCtx.settings.installSection(ctx, FREE_SEARCH_NS, Config, config ?? {}, {
1744
+ setSource: (source) => {
1745
+ current = source;
1746
+ },
1747
+ onChange: () => {
1748
+ // settings 变更时刷新系统提示词(显示最新引擎)
1749
+ if (typeof refreshPrompt === "function") refreshPrompt();
1750
+ },
1751
+ });
1744
1752
  });
1745
1753
 
1746
1754
  ctx.inject(["webServer", "settings"], (sctx) => {
@@ -2032,7 +2040,7 @@ function apply(ctx, config) {
2032
2040
  },
2033
2041
  engine: {
2034
2042
  type: "string",
2035
- description: "Optional specific engine to try first: ddg, ddg-lite, bing, searxng, anysearch, exa, tavily, keenable, perplexity, deepseek-official.",
2043
+ description: "Optional specific engine to try first: ddg, ddg-lite, bing, searxng, anysearch, exa, tavily, keenable, perplexity, deepseek-official, gemini.",
2036
2044
  },
2037
2045
  },
2038
2046
  output: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darlingc/dsh-freesearch",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "Free web search for DeepSeek Harness: 11 engines (Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable keyless + Gemini grounding) + time filtering + platform search + web_fetch, with web settings UI.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",