DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Web Search — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

@ian_p/dsh-web-search

Web Search

Multi-provider third-party web search for the DeepSeek Harness: routes the native web_search tool through a configurable provider fallback chain, with an isolated provider settings page.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add @ian_p/dsh-web-search@0.1.5-rc.3
READMECompatibilityVersions

Compatibility and provenance

Web Search is published as @ian_p/dsh-web-search and currently resolves to version 0.1.5-rc.3. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
9/23/2026

Versions

0.1.5-rc.3prerelease
9/23/2026

Related plugins

Loading related plugins…

Latest
0.1.5-rc.3
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
128.1 kB
Files
9
Surface
web
License
MIT
Source
npm
GitHub
★ 0
Weekly downloads
0
Last push
9/23/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in search-research.

Weknora@wxg-prc-cpg/dsh-weknoraWeKnora knowledge retrieval tools for DeepSeek Harness (dsh): semantic search, document reading and RAG/agent answers over your own knowledge bases.Find Plugindsh-find-pluginFind DeepSeek Harness plugins inside the agent — live GitHub dsh-plugin topic search, ranked by stars.Builtin Browserdsh-builtin-browserShared real browser plugin for DeepSeek Harness: install-and-use — a visible native browser the human can take over, driven by the agent over CDP. DOM-level interaction (React/Vue safe), per-task session isolation, cookie persistence (browser_auth), CAPTCBrowser@anweat/dsh-browserSelf-contained browser runtime plugin for DeepSeek Harness (scoped @anweat) — bundles Playwright (chromium) and OpenCLI as plugin-local dependencies (with global-reuse fallback), exposes a `browser` service and interactive browser tools.

README

English · 简体中文

One fallback chain. Eight providers.

@ian_p/dsh-web-search is a Cordis plugin for the DeepSeek Harness that replaces the native web_search back end with a configurable, multi-provider chain. Each query walks the configured provider order and falls back to the next on failure or empty results; DuckDuckGo needs no key and closes the chain.

The browser half adds a dedicated Search providers settings page for keys, connection tests and drag-to-reorder.

Design reference: the multi-provider approach is adapted from Oh My Pi (OMP).

CapabilityWhat it changes
8 providers, one chainTavily, Brave, Exa, Firecrawl, Jina, Kagi, SearXNG, DuckDuckGo — any order, any subset.
Native web_search integrationThe patch override routes the harness's own web_search tool through this chain.
Fail-loudWith the patch not applied the native tool reports WEB_PROVIDER_AMBIGUOUS instead of silently degrading.
Host-native settings pageLocalized (en/zh) through the host locale service and styled with the host's own control contract (--dsw-* design tokens), so it follows the host language and light/dark theme.
Auditable fallbackOne host-log line per search names every provider that was skipped or failed, then the one that served.

Requirements

  • Node.js ^22.19 or >=24

  • DeepSeek Harness 0.1.5-rc.3 — this plugin hand-writes its Typert Remote descriptors, so it targets one DSH train:

    npm install --global @deepseek-ai/dsh@0.1.5-rc.3
    

    Every @deepseek-ai/dsh* service it injects (web, credentials, typert) comes from that host build, so those packages are declared as peers at the same train version rather than listed package by package. The components declared on their own:

    ComponentVersionRole
    @deepseek-ai/dsh0.1.5-rc.3Host runtime (source of every @deepseek-ai/dsh* peer)
    @deepseek-ai/cordis^4.0.2Plugin/context framework (peer + dev)
    react^18.2Browser half only (dev)
    typescript^7.0.2Type check over src/host-core.js (dev)

Installation

From npm (the package declares dsh.bundle.patch, so dsh plugin add also activates the profile bundle):

dsh plugin --profile web add @ian_p/dsh-web-search

Local development — run inside the harness source workspace; the overlay loads src/index.js directly, so no build step is needed:

pnpm dsh web --patch /path/to/dsh-web-search/patch.web.yml

web is the launcher's alias for --profile web. The overlay (patch.web.yml) inserts the plugin row and sets searchProvider: dsh-web-search on the native web row; the browser half is discovered through the dsh.client manifest plus exports["./client"].

Linked checkout (dsh plugin --profile web add "link:/path/to/checkout") loads the published shape instead, i.e. dist/ — run pnpm run build after editing src/ (pnpm install also builds it through the prepare script). A host restart is required either way.

How the chain behaves

Order comes from the settings page (drag to reorder) and is stored in the dsh-web-search/config credential record. Resolution: your ordered, non-excluded providers first, then every remaining provider in built-in order.

For each provider, in order:

  1. available() — a local check, no network call: keyed providers need a credential record, SearXNG needs its endpoint, DuckDuckGo is always available. Not available ⇒ skipped.
  2. search() with a per-provider timeout (default 60 s, timeout in the config record).
  3. Success means a non-empty answer or at least one source; then the search returns immediately — later providers are never tried. There is no racing, no merging of providers, no retry and no cache.
  4. Failure means HTTP non-2xx, invalid JSON, a thrown error, or "no renderable content"; the reason is recorded and the next provider is tried.

If every provider fails, the error names the last provider tried, and the plugin then retries the native deepseek-official provider before giving up.

Each search logs one line to the host log:

[14:32:07] [dsh-web-search] firecrawl: HTTP 429: ... → tavily: served (8 sources, 4437ms)
[14:32:09] [dsh-web-search] trying exa
[14:33:01] [dsh-web-search] brave: not configured → ... → all providers failed

A trying line with no completion line after it means that provider is still in flight (the harness log itself is not timestamped, so the plugin stamps its own lines).

Providers

IDLabelKindHow to activate
tavilyTavilyAPI keySave a Tavily API key
braveBraveAPI keySave a Brave API key
exaExaAPI keySave an Exa API key
firecrawlFirecrawlAPI keySave a Firecrawl API key
jinaJinaAPI keySave a Jina API key
kagiKagiAPI keySave a Kagi API key
searxngSearXNGEndpointSave a SearXNG instance endpoint
duckduckgoDuckDuckGoNoneAlways available (default final fallback)

Per-provider details worth knowing:

  • Tavily — results[].content is a page chunk, not a description, so the request asks for chunks_per_source: 1 (one relevant passage instead of three chunks of page chrome) and include_published_date: true.
  • Firecrawl — reports its own failures as HTTP 200 with success: false plus a warning; that is surfaced as the provider's failure reason instead of looking like an empty result set.
  • DuckDuckGo — keyless; the HTML front end is parsed, and a bot-challenge page yields zero sources so the chain keeps going.
  • SearXNG — self-hosted; week recency maps to month because the instance only understands day/month/year.

Configuration

Credentials

All provider secrets live in harness credential records under the dsh-web-search/ scope, managed from the settings page — no environment variables. (Environment-variable credential refs would shadow saved values and stop the page from working.)

  • API-key providers — an api-key record, e.g. dsh-web-search/tavily.

  • SearXNG — a grant record carrying the instance endpoint.

  • DuckDuckGo — no key.

  • Plugin config — a grant record at dsh-web-search/config:

    order: [firecrawl, tavily, brave, exa, jina, kagi, searxng, duckduckgo]
    exclude: []
    timeout: 60        # seconds, per provider
    

    The settings page writes order; exclude and timeout currently only via the record.

Settings page

Registered as the isolated settings section Search providers (id web-search-providers, order 12), separate from the native web-search config page. It lists providers in effective fallback order and lets you save or clear a key/endpoint, run a connection test, and drag the cards to reorder the chain. It talks to the host over the plugin's websearch Remote namespace (list / setKey / unsetKey / setOrder / testProvider).

The page registers en / zh dictionaries with the host locale service (sidebar label included) and paints itself with --dsw-* tokens using the host's own button, input and card geometry, so both language and theme follow the host.

What the harness receives

web_search results are shaped to match the native path:

  • Sources carry url, title?, snippet?, publishedAt? only. Snippets are cleaned (markdown headings stripped, whitespace collapsed, chunk separators removed) and held to 150 characters — the documented ceiling of the native citation excerpt — with a cut marked by ….
  • The provider's own answer (Tavily and Exa produce one) is passed as content, bounded to 400 characters, and rendered as Markdown above the source list. The native provider never sends one.
  • Truncation is the seam's decision. The plugin hands back the provider's full source list with truncated: false; the harness caps it to request.maxResults and sets truncated: true, which is what surfaces the "sources truncated" notice to both the user and the model.
  • The tool has no field for the serving provider, so it is reported on the host log instead (see above).

Architecture / project layout

dsh-web-search/
├── patch.web.yml            # --patch overlay for local development (relative ./src/index.js)
├── cordis.patch.yml         # published bundle patch (package specifier), declared via dsh.bundle.patch
├── src/                     # source of truth (never published)
│   ├── index.js             # host entry: ctx.web provider, chain orchestration, credential RPC ops
│   ├── host-core.js         # pure functions: query parsing, per-provider request building and
│   │                        # response normalization, snippet/answer policy
│   ├── remote.js            # websearch Remote namespace (WebSearchController)
│   └── client/bundle.js     # browser half: hand-written __ModuleLoader__ factory bundle (no bundler):
│                            # the settings page and its single-copy state machine
├── scripts/build.mjs        # build: clean copy of src/ → dist/ (the publishable tree)
├── dist/                    # build output — published to npm, git-ignored
├── tests/                   # 134 pure + 12 environment-dependent tests (see below)
├── docs/DESIGN.md           # host contracts this plugin depends on, and why the code is shaped this way
└── package.json             # main/exports → dist/, files: ["dist/", …], prepare builds dist/

Development / Testing

pnpm install             # installs peers/dev deps and runs `prepare`, which builds dist/
pnpm run build           # stage dist/ from src/ (clean copy, no bundler, no new dependency)
pnpm test                # 134 pure-function tests (node:test, zero dependencies)
pnpm run test:rpc        # 12 environment-dependent tests (resolves the 0.1.5-rc.3 peers)
pnpm run typecheck       # tsc -p tsconfig.types.json (JSDoc types of src/host-core.js)
pnpm run prepublishOnly  # build + both test tiers + typecheck, before a publish
TierSuiteCountWhat it covers
Puretests/host-core.test.mjs97query parsing, provider request bodies, response normalization, snippet/answer policy, credential-record helpers
Puretests/interaction.test.mjs37the settings page state machine, run against the shipped client bundle
Envtests/remote-contract.test.mjs11the Typert Remote contribution against the installed host contract
Envtests/client-bundle.smoke.mjs1bundle registration, apply(), and the injected stylesheet

src/index.js (the host entry: transport, chain, credential ops, ctx.web injection) has no test coverage — it needs the harness runtime; docs/DESIGN.md records what that leaves unpinned.

License

MIT © ForeverYoungPp