DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Websearch Stack — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
W

dsh-websearch-stack

Websearch Stack

适用于 DeepSeek Harness 的多提供商网页搜索栈:无需密钥的默认设置、有序回退链,以及自托管的 SearXNG 选项。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:orfeomorello/dsh-websearch-stack#d5d17982ce7e1f351e678fcef1b29730143b14b8
README兼容性版本

兼容性与来源证明

Websearch Stack 以 dsh-websearch-stack 发布,当前版本为 0.1.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/10

版本

0.1.0stable
2026/10/10

相关插件

正在加载相关插件…

最新版
0.1.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 1
周下载
0
最近提交
2026/10/10
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 search-research 分类下经过校验的插件。

Weknora@wxg-prc-cpg/dsh-weknora适用于 DeepSeek Harness (dsh) 的 WeKnora 知识检索工具:通过自有知识库进行语义搜索、文档阅读以及 RAG/代理回答。Free Searchdsh-free-searchDeepSeek Harness 的免费网页搜索:24 个引擎(Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable/Firecrawl/Parallel 无需密钥;通过 MCP 使用 Zhihu 全局/站内搜索,以及 Perplexity/SerpBase/DeepSeek/You.com/Baidu/Kimi/Aliyun/Doubao,需密钥;OpenAI/Gemini/ClaudeDejadsh-dejaDeepSeek Harness 的 deja-vu 记忆:其他 40 个编码代理的会话历史,可搜索,并在每个步骤前调用——本地索引,无需 LLM。Builtin Browserdsh-builtin-browser适用于 DeepSeek Harness 的共享真实浏览器插件:安装即用——可由人类接管的可见原生浏览器,并由代理通过 CDP 驱动。DOM 级交互(兼容 React/Vue)、按任务隔离会话、Cookie 持久化(dsh_browser_auth)、C

README

dsh-websearch-stack

Multi-provider web search for DeepSeek Harness (dsh). The plugin registers one search provider on the ctx.web seam; that provider runs an ordered fallback chain over the backends you enable.

Status: v0.1.0, MVP. Six backends implemented and unit-tested. Verified live: Tavily keyless and Parallel MCP. The others need an API key or a local instance and are not yet verified — see Known limitations.

Features

  • Six search backends: Tavily (keyless-capable), Parallel MCP (no credentials), SearXNG (self-hosted), Brave, TinyFish, Exa.
  • Ordered fallback chain: a recoverable error (network, timeout, rate limit, bad response) moves to the next backend; a terminal one aborts; if all fail the error lists every attempt.
  • Keys without a restart: the four key-backed backends are configured from the web client's Plugins page, written through the Host's credential store and resolved per request — never into a settings file, with environment variables as the fallback.
  • Boot-time chain: the chain order, the SearXNG URL, the result cap, the timeout and the cache TTL are volatile fields set from your profile's patch layer (see Configuration).

Install

lib/ is committed, so installing from GitHub needs no build step.

dsh plugin --profile web add github:orfeomorello/dsh-websearch-stack

To try on a disposable profile first:

dsh --profile web --dump-config > before.txt
dsh plugin --profile web add github:orfeomorello/dsh-websearch-stack
dsh --profile web --dump-config > after.txt

Quick start

The default chain ['tavily', 'parallel-mcp'] works with no key and no configuration: Tavily runs keyless, Parallel needs no credentials. Install the plugin, restart the profile, and ask anything that needs current information — web_search answers through the chain.

From there:

  • want more or different sources? reorder the chain or add a backend in the profile patch (see Configuration) — SearXNG, Brave, TinyFish and Exa each need their own setup;
  • want your own instance? follow SearXNG: no external API, no key, your infra;
  • want higher-quality Tavily results or Brave/Exa? paste a key on the plugin's page in the web client; it takes effect on the next request.

Configuration

Two surfaces, because the web client's Plugins page can only write credentials:

WhatWhereWhen it takes effect
API keys (TAVILY_API_KEY, BRAVE_SEARCH_API_KEY, TINYFISH_API_KEY, EXA_API_KEY)the Plugins page → this bundle's page, through the settings cardthe next request, no restart
enabled_providers, searxng_url, default_max_results, default_timeout_ms, cache_ttl_secondsyour profile's cordis.patch.yml (or a --patch overlay)at the next profile boot

The second list is a host limitation, not a plugin one: in @deepseek-ai/dsh-client-ui-plugin-manager 0.2.0-rc.2 the page renders plugins.bundle.config without a config form, so a bundle's own fields never get a widget. The fields are declared volatile (each one a reference the Host can rewrite in place), so a form written against plugins.row.config — or any CLI tooling that writes the namespace — would apply them live; today the profile patch is the way.

Boot-time values

The values live in the profile's own patch layer, $DSH_HOME/profiles/<profile>/cordis.patch.yml, keyed by this plugin's row id. This shape is verified with dsh --profile <profile> --dump-config:

# ~/.dsh/profiles/web/cordis.patch.yml
- id: websearch-stack
  name: dsh-websearch-stack
  config:
    enabled_providers: [tavily, parallel-mcp]
    default_max_results: 5

For a one-off try without touching the file, an overlay applied after every other layer:

dsh --profile web --patch ./searxng.yml
# searxng.yml
- id: websearch-stack
  name: dsh-websearch-stack
  config:
    enabled_providers: [searxng, tavily]
    searxng_url: http://localhost:8080

An absent field keeps its default. An unknown value is refused by the schema, so a typo fails the boot instead of silently disabling a backend.

A Compose-style setup can keep the URL in the environment instead: the entry-list YAML dialect evaluates !!js scalars at entry activation, with Node globals in scope.

# ~/.dsh/profiles/web/cordis.patch.yml
- id: websearch-stack
  name: dsh-websearch-stack
  config:
    enabled_providers: [searxng, tavily]
    searxng_url: !!js process.env.SEARXNG_URL ?? ''

--dump-config prints the expression node unevaluated — the dump is the stored patch, not the resolved value.

OptionDefaultMeaning
enabled_providers['tavily', 'parallel-mcp']Fallback chain, in order. Values: tavily, parallel-mcp, searxng, brave, tinyfish, exa. An empty list disables the plugin (see How the fallback works).
searxng_url—Base URL of a self-hosted SearXNG instance, e.g. http://localhost:8080. Required for searxng.
default_max_results5Maximum sources per query when the request names none (1–20).
default_timeout_ms10000Per-backend request timeout in milliseconds (1 000–60 000).
cache_ttl_seconds60Cache TTL for identical queries. 0 disables the cache.

SearXNG

The self-hosted option: your instance, no external API, no key. It needs two things — an instance with the JSON format enabled, and searxng_url pointing at it.

  1. Run an instance (Docker Compose, the project's recommended layout):
mkdir -p ./searxng/core-config/
cd ./searxng/
curl -fsSLO https://raw.githubusercontent.com/searxng/searxng/master/container/docker-compose.yml
curl -fsSLO https://raw.githubusercontent.com/searxng/searxng/master/container/.env.example
cp -i .env.example .env
docker compose up -d
  1. Enable the JSON format in core-config/settings.yml — json is not in the default search.formats (html only):
search:
  formats:
    - html
    - json
  1. Point the plugin at it (profile patch, then restart the profile):
- id: websearch-stack
  name: dsh-websearch-stack
  config:
    enabled_providers: [searxng, tavily, parallel-mcp]
    searxng_url: http://localhost:8080

The backend calls GET <searxng_url>/search?q=…&format=json&language=en and reads results[].{url,title,content}. Without searxng_url the backend reports itself unavailable and the chain moves on. SearXNG's own installation details are in its container and search: settings pages.

Backends

IdKeyNotes
tavilyTAVILY_API_KEY (optional)Without a key sends x-tavily-access-mode: keyless (verified live). With a key, Bearer.
parallel-mcpnoneJSON-RPC tools/call on web_search (arguments objective and search_queries), no credentials. Verified live.
searxngnoneSelf-hosted instance, requires searxng_url. Not verified (needs an instance).
braveBRAVE_SEARCH_API_KEYX-Subscription-Token. Not verified with a real key.
tinyfishTINYFISH_API_KEYX-API-Key. Not verified with a real key.
exaEXA_API_KEYx-api-key, POST /search. Not verified with a real key.

Keys are read from the Host credential store, with the environment variables above as the fallback: a key written from the settings card is resolved per request, so it needs no environment export. The config YAML never holds secrets.

Settings card (web client)

The plugin ships a configuration card for the dsh web client (dsh.client.platform: "web"). It appears on the Plugins page under the dsh-websearch-stack bundle and manages the four key-backed API keys through the Host's credentials service:

  • the state badge shows only whether a key is configured (describe), never the value;
  • what you write lands in the Host credential store (e.g. $DSH_HOME/.credentials.yaml), not in any settings document;
  • the provider re-resolves the reference on the Host's credentials/reference-updated event, so a key written from the page takes effect on the next request without a reboot;
  • a field left blank does not clear the stored key;
  • each field is named after its provider — Tavily API key, Brave Search API key, TinyFish API key, Exa API key — and the Search providers section below links every backend to its owner's site (see below).

UI status: the page and the card were exercised in a live web client (the bundle page, its title, the key controls and the providers section render). What the host does not render is a form for this bundle's own config fields — see Configuration and Known limitations.

What the plugin page shows

The Plugins page's detail for this bundle states the bundle's own identity — its display title from locale/en.json, its version, and the package name (the one you install elsewhere, in a <code> line) — then this plugin's configuration: the four key controls, named after their provider, and a Search providers section listing every backend the chain vocabulary accepts:

ProviderWhat it takesWhere to configure
TavilyAPI key optional (works keyless)https://app.tavily.com/home
ParallelNo key neededhttps://docs.parallel.ai/
SearXNGSelf-hosted instancehttps://docs.searxng.org/
Brave SearchAPI keyhttps://brave.com/search/api/
TinyFishAPI keyhttps://docs.tinyfish.ai/search-api/reference
ExaAPI keyhttps://exa.ai/

Each row links to its owner's site, where a key is created or the service is documented. The section is the bundle's contribution to the page's plugins.detail.section slot; the copy lives in src/client/card.ts.

Coexisting with the native DeepSeek provider

The web profile already ships web-search-deepseek (provider id deepseek-official), and @deepseek-ai/dsh-base pins the seam to it:

- id: web
  name: '@deepseek-ai/dsh-web'
  config:
    searchProvider: deepseek-official
    fetchProvider: http

That pin is the whole problem for any third-party search provider: the DeepSeek provider's available() is true even without DEEPSEEK_API_KEY (it resolves the credential per search, not at selection time), so with the pin in force every web_search fails with WEB_PROVIDER_CREDENTIAL_MISSING and never reaches a provider this bundle registers.

This bundle's cordis.patch.yml therefore overrides that row (later bundle layers win; the profile's own patch, the home patch and --patch overlays are later still and can pin anything they want):

- id: web
  name: '@deepseek-ai/dsh-web'
  config:
    searchProvider: websearch-stack
    fetchProvider: http

A patch replaces the matched row's whole config — never a deep merge — so fetchProvider: http is restated exactly as the base row leaves it. Without @deepseek-ai/dsh-base in the profile the web row does not exist, the override is skipped with a loader warning, and the seam auto-selects this provider as the only usable one.

To hand web_search back to the native provider, re-pin it in your profile's cordis.patch.yml (or --patch), restating both keys:

- id: web
  config:
    searchProvider: deepseek-official
    fetchProvider: http

How the fallback works

The seam accepts a single usable search provider when none is configured. So the plugin registers exactly one provider, websearch-stack, that walks the backends in order:

  • a backend that is not available (no key, no SearXNG URL) is skipped before any request;
  • a recoverable error (network, timeout, rate limit, invalid response, auth or credits) moves to the next backend;
  • a terminal error (e.g. cancellation) stops the chain and rethrows;
  • if all fail, the error lists every attempt.

The chain order is read on every request, so an edit to enabled_providers in the profile patch takes effect from the next boot, and every backend in the chain is re-resolved per request. When the chain is empty — or every backend in it is unavailable — available() is false and the seam answers WEB_PROVIDER_CONFIGURED_UNAVAILABLE, because the bundle patch pins searchProvider to this provider. Re-add a backend in the profile patch to make web_search work again.

Development

npm install
npm run typecheck     # tsc --noEmit
npm test              # unit/integration tests (node:test)
npm run build         # rebuild lib/ from src/ (also emits the client bundle)
npm run bundle:client # rebuild only lib/client.js (ModuleLoader bundle)

lib/ is committed. After changing src/, run npm run build and commit lib/ too — CI fails if they drift apart.

Known limitations

  • Live services partially verified. Tavily keyless and Parallel MCP verified live. Brave, TinyFish, Exa and SearXNG are not yet: they need API keys or a local instance.
  • The chain is not editable from the web client. The Plugins page renders a bundle's configuration card (the API keys here) but not a form for the bundle's own config fields: in @deepseek-ai/dsh-client-ui-plugin-manager 0.2.0-rc.2, plugins.bundle.config is rendered without the form prop, while plugins.row.config receives it. A plugins.row.config entry for the plugin's row could close this gap; until then, edit $DSH_HOME/profiles/<profile>/cordis.patch.yml and restart the profile (see Configuration).
  • Pinned seam, by design. The bundle patch pins web.searchProvider to websearch-stack, because the base profile pins it to the DeepSeek provider, which is available() without a key. Consequence: with an empty chain web_search fails with WEB_PROVIDER_CONFIGURED_UNAVAILABLE instead of falling back to the native provider (see Coexisting with the native DeepSeek provider).
  • No fetch. Page fetching is handled by DSH's dsh-web-fetch-http provider, not this plugin.
  • Not a sandbox. The code runs inside the host process with its privileges, like every dsh plugin.

License

MIT — see LICENSE.