A3Boy
dsh-web-tools
Multi-provider Web Search & Fetch for DeepSeek Harness — Tavily, Exa, Firecrawl, Brave, You.com, Jina & SearXNG with fallback and native settings UI.
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 15, 2026
- Updated
- Aug 15, 2026
Introduction
dsh-web-tools
Configurable multi-search-source backends for DeepSeek Harness's
web_search / web_fetch.
Configure Tavily, Exa, Firecrawl, Brave, You.com, Jina, or SearXNG — when one
source is rate-limited, exhausted, or down, the plugin switches to the next in
your configured order. The agent keeps using DSH's original web_search /
web_fetch; no new tools are added.
BYOK · API keys live in DSH Credentials and requests go directly to each provider — no intermediary server.
English | 简体中文
7 Providers · Native DSH tools · Fallback · BYOK · SearXNG
Why
- 7 search providers: Tavily, Exa, Firecrawl, Brave, You.com, Jina, SearXNG
- Native DSH tools only: the model sees just
web_search/web_fetch— notavily_search-style provider tools - Custom priority: default provider + ordered fallback chain
- Multi-key + health + quota: credential pools, provider health, quota state
- Native DSH settings page: providers, credentials, connection tests, and test search in one place
Quick Start
Requirements
- DeepSeek Harness: developed and tested against
0.1.0-rc.6 - Uses the DSH
webprofile - Installing external bundles requires
pnpm - Commercial providers use your own API keys; SearXNG works with no commercial API key
Install
dsh plugin --profile web add github:A3Boy/dsh-web-tools
Restart dsh web, then open the plugin settings page to configure providers.
The plugin integrates through DSH's official Profile Bundle mechanism —
no Harness core changes.
# check the composed config
dsh --profile web --dump-config
# update / remove
dsh plugin --profile web update dsh-web-tools
dsh plugin --profile web remove dsh-web-tools
Configure providers
Settings → Plugins → Plugin configuration → dsh-web-tools- Fill in API keys per provider (comma-separated keys → credential pool)
- Pick the default provider and adjust the fallback order
- Use Test Search to run a real query and verify
Providers
| Provider | Search | Fetch | Best for |
|---|---|---|---|
| Tavily | ✅ | ✅ | General agent search |
| Exa | ✅ | ✅ | Semantic / research |
| Firecrawl | ✅ | ✅ | Reading pages after search |
| Brave Search | ✅ | — | Traditional web search |
| You.com | ✅ | — | Web / News |
| Jina | ✅ | ✅ | Page content reading |
| SearXNG | ✅ | — | Self-hosted |
Not sure which one?
- General: Tavily
- Research / semantic: Exa
- Need to read pages: Firecrawl / Jina
- Traditional web search: Brave
- Self-hosted / privacy: SearXNG
Provider selection reference: free tiers & pricing (2026-08-16)
| Provider | Free allowance | Type | Billing |
|---|---|---|---|
| Tavily | 1,000 credits / month | monthly | credits (Basic=1) |
| Exa | $20 signup + $10/mo | signup + monthly | per request ($7/1k) |
| Firecrawl | 1,000 credits + 1,000 search credits / mo | monthly | 2 credits per 10 results |
| Brave | $5/mo ≈ 1,000 searches | monthly | per request ($5/1k) |
| You.com | $100 one-time | one-time | per call ($5/1k) |
| Jina | 10M tokens one-time | one-time | per token |
| SearXNG | no platform quota | self-hosted | none |
Pricing and free tiers come from upstream sites and may change — always check each provider's site.
Fallback
The attempt order for one search:
Tavily → Exa → Brave → SearXNG
On a recoverable failure of the default provider, the next one is tried:
401 / 403 · 408 · 429 · 5xx · network error · timeout · provider unavailable
A credential that fails auth is marked unhealthy while the search continues.
These errors do not switch providers: 400 bad request, local
configuration errors.
Caller cancellation (abort) terminates the whole search chain immediately — it never falls back.
Settings
Configuration entry:
Settings → Plugins → Plugin configuration → dsh-web-tools
Manages: enable toggle, default provider, fallback order, per-attempt timeout, provider enable/disable, API keys / credential pools, base URLs, connection tests, quota state, test search.
Result count and the overall search timeout are owned by the DSH tool layer (
web_search); the plugin does not override them. The settings page's per-attempt timeout is how long a single provider may run before the plugin aborts it and tries the next one.
Credentials & Quota
Credential pools
Each provider can hold multiple API keys:
Tavily
├── Key A
├── Key B
└── Key C
Keys are selected least-used-first; a failing key is marked unhealthy and skipped; when all keys are unavailable, health resets. Values can be separated by commas, whitespace, newlines, or semicolons.
Credential pools are for legitimate scenarios (team keys, workspaces, key rollover, environment isolation) — not for bypassing provider limits.
Quota
Providers use different units (credits / requests / tokens / USD / self-hosted); the plugin does not force them into one percentage.
Quota is split into authoritative and best-effort for display in the settings page. Quota does not drive search routing — fallback is triggered by real request failures (402 / 429, etc.).
| Provider | Data source | Status |
|---|---|---|
| Tavily | Official /usage | ✅ implemented |
| Firecrawl | Official /v2/team/credit-usage | ✅ implemented |
| You.com | Official Account Balance API | ✅ implemented |
| Exa | no public balance API | local estimate (non-authoritative) |
| Brave | X-RateLimit-* headers | parsing ready, full display pending |
| Jina | Reader balance info | best-effort |
| SearXNG | no platform quota | self-hosted |
For multi-key pools, quota queries the FIRST key in the pool; the settings page marks it as such. Quota failures only affect display; results are cached 5 minutes (no polling).
A quota lookup failure only affects display — never search.
Search & Fetch
web_search → candidate URLs → web_fetch → read page content
Tavily, Exa, Firecrawl, and Jina use their native content-fetch capabilities; Brave, You.com, and SearXNG are used for search.
Note:
web_fetchwalks fetch-capable providers in search priority order, but it does NOT reuse the provider thatweb_searchactually hit, and it does not guarantee the target page's real HTTP status / final URL (provider native extract usually returns clean text). For strict Fetch semantics (real status / redirects / truncation), rely on DSH's official HTTP Fetch; use this plugin's provider extract for content enhancement.
Security & Privacy
- API keys are resolved on the Host only — full credentials never reach the browser (only configured/masked state).
- Test results and logs never return full API keys.
- Config writes are restricted to the local configuration plane.
- No dsh-web-tools remote server, no shared keys.
- No search usage telemetry uploaded.
- Can run with self-hosted SearXNG only.
Compatibility / Limitations
- Developed and tested against DeepSeek Harness
0.1.0-rc.6; DSH is a developer preview and may introduce breaking changes. - Brave quota full display is pending (header parsing exists).
web_fetchdoes not guarantee real HTTP status / final URL semantics (see Search & Fetch).- SearXNG quality depends on the instance and the upstream engines it enables.
- Free tiers/pricing come from upstream and may change.
Architecture
flowchart TD
Agent[DSH Agent] -->|web_search / web_fetch| Tool[dsh-tool-web]
Tool --> Web[ctx.web]
Web -->|searchProvider: dsh-web-tools| Hub[SearchHubProvider]
Hub --> Registry[Provider Registry]
Hub --> FB[Fallback]
Hub --> Pools[Credential Pools]
Hub --> Quota[Quota]
Hub --> Health[Health / Stats]
Registry --> T[Tavily]
Registry --> E[Exa]
Registry --> F[Firecrawl]
Registry --> B[Brave]
Registry --> Y[You.com]
Registry --> J[Jina]
Registry --> S[SearXNG]
Settings ↔ Host:
flowchart LR
Client[Web Client] -->|/web-tools/api/*| Routes[Host routes]
Routes --> Cfg[config]
Routes --> Cred[credentials]
Routes --> Test[provider test]
Routes --> TS[test search]
Routes --> Q[quota]
Cfg --> S1[ctx.settings]
Cred --> S2[ctx.credentials]
Routing uses no extra LLM requests and adds no model-visible tools.
Verification
| Item | Status |
|---|---|
| TypeScript / Build | ✅ |
| Unit (pool / fallback / Jina / Brave header) | ✅ |
| Route smoke (config · credential no-leak · quota · persist-before-ok · loopback/cross-site 403) | ✅ |
| Runtime invariants (abort no-fallback · timeout real-abort then fallback · 401 marks key · fetch key rotation) | ✅ |
| Tavily Search + Quota | ✅ E2E |
| Exa Search + credential pool | ✅ E2E |
| Firecrawl Search + Fetch + Quota | ✅ E2E |
| Brave / You / Jina / SearXNG | adapter ready, E2E pending |
Development
npm install
npx tsc -p tsconfig.json --noEmit # Host
npx tsc -p tsconfig.client.json --noEmit # Client
npx tsc -p tsconfig.build.json # Build
npm test # Unit + route smoke + runtime invariants
Local development needs DSH peer deps resolvable (link to the DSH profile's
node_modules). If the plugin is missing from --dump-config, check bundle
loading; if the settings card is missing, fully restart dsh web.
Provider development
Provider adapters live in src/host/providers/. Add a provider by
implementing the ProviderAdapter contract and registering it; provide Fetch
/ Quota implementations if supported. The agent side needs no new tools. See
CONTRIBUTING.md.
Roadmap
- Brave quota full display (header parsing exists)
- Serper, Parallel (OAuth), Perplexity providers
- Real per-provider comparison and usage history
- Optional: route
web_fetchback to DSH's official HTTP Fetch semantics
Install with your coding agent
Expand the prompt
Install dsh-web-tools from:
https://github.com/A3Boy/dsh-web-tools
Requirements:
- Use the current DSH profile's standard plugin install flow.
- Do not read, print, or ask me to paste API keys.
- Do not modify DeepSeek Harness core.
- After installing, check the composed config with
`dsh --profile web --dump-config`.
- Do not terminate or restart a running DSH process without asking.
- Report whether the plugin made it into the web profile.
Contributing
Issues and PRs are welcome. Before adding a search provider, review the existing adapters and CONTRIBUTING.md, and keep the provider layer simple.
License
MIT © A3Boy