dsh-9router-web-search
Manifest validโ 1DSH plugin: 9router-backed web search and web fetch providers
๐ dsh-9router-web-search
Web search & fetch for DeepSeek Harness, powered by 9router. Wires the native
web_searchandweb_fetchtools into 9router's/v1/searchand/v1/web/fetchendpoints โ no server-side search tool required.
๐บ๐ธ English ยท ๐จ๐ณ ็ฎไฝไธญๆ
โจ What it does
- ๐ Search provider โ routes DSH's native
web_searchthrough 9router's/v1/search, returning deduplicatedWebSourceresults (title, snippet, published date). - ๐ Fetch provider โ routes DSH's native
web_fetchthrough 9router's/v1/web/fetch, returning clean text/markdown bodies. - ๐๏ธ Settings card โ a native DSH settings panel for the API key, base URL, models, timeouts, and limits.
- ๐งฉ Zero-config wiring โ the bundle patch pins the web seam's search and fetch to
9router; no manual provider configuration. - ๐ Credentials-aware, key-optional โ resolves the API key from DSH's credentials service (
NINE_ROUTER_API_KEY) or a literal config value; keyless local 9router instances work out of the box; never committed to the repo. - ๐งฑ Zero build โ pure ESM, plain JavaScript, no bundler required.
๐งญ Why this plugin
DSH's default web_search uses the web-search-deepseek provider, which requires the upstream service to implement Anthropic's web_search_20250305 server-side search tool and return web_search_tool_result blocks.
9router is an OpenAI-compatible gateway: it passes that tool definition to the model as a regular function instead of executing searches server-side โ so it cannot provide native search by itself.
web-search-deepseek (default) | 9router (this plugin) | |
|---|---|---|
| Requires | Anthropic web_search_20250305 server-side tool | Any 9router-compatible gateway |
| Works with 9router | โ | โ |
| Search endpoint | model-provided | POST /v1/search |
| Fetch endpoint | model-provided | POST /v1/web/fetch |
This plugin calls 9router's own endpoints directly and maps their responses to the WebSource and WebFetchBody types expected by the DSH web seam.
โ๏ธ How it works
web_search / web_fetch (native DSH tools)
โ
โผ
ctx.web seam
โ provider = "9router"
โผ
dsh-9router-web-search
โโโ search โ POST {baseURL}/search โ WebSource[]
โโโ fetch โ POST {baseURL}/web/fetch โ WebFetchBody
โ
โผ
9router gateway
โ
โผ
9router providers / model combos
Errors surface as machine-routable WebError codes (WEB_PROVIDER_ERROR, WEB_TIMEOUT, WEB_ABORTED, WEB_PROVIDER_CREDENTIAL_MISSING); transient network and 5xx failures are retried with backoff; non-2xx fetch responses come back as results โ never silent throws.
๐ Quick start
1. Install the plugin
npx @deepseek-ai/dsh plugin --profile web add github:lordraiden/dsh-9router-web-search
2. Wire it up
- The plugin's bundle patch already pins
web.searchProviderandweb.fetchProviderto9routerโ no manual wiring needed (a profile's owncordis.patch.ymlcan override the row). - Set a
baseURLin the settings card (or aNINE_ROUTER_BASE_URLenvironment value) pointing at your 9router gateway โ there is no implicit fallback endpoint; without a configured endpoint the provider reports itself unavailable. - If your 9router instance requires a key, store
NINE_ROUTER_API_KEYin DSH's credentials โ the settings card's API key field writes it there โ or set a literalapiKeyin the plugin settings. The secret is write-only in the UI and is never stored in this repo. Keyless instances work without any credential.
3. Restart & refresh
Restart Harness, then hard-refresh the browser. The 9router options appear in the web settings card.
๐ Reproducible installs โ append a release tag (or commit SHA) to pin an exact version:
npx @deepseek-ai/dsh plugin --profile web add github:lordraiden/dsh-9router-web-search#v0.2.3
๐ ๏ธ Configuration
| Key | Type | Default | Description |
|---|---|---|---|
baseURL | string | โ | Base URL of your 9router-compatible API (http/https only); resolved as explicit setting โ NINE_ROUTER_BASE_URL env โ absent (provider unavailable) |
searchModel | string | search-combo | Model name for the search endpoint |
fetchModel | string | fetch-combo | Model name for the fetch endpoint |
searchType | string | web | search_type sent to the search endpoint |
defaultMaxResults | number | 8 | Source cap used only when a search request does not specify maxResults (the DSH seam enforces the per-operation limit) |
timeoutMs | number | 30000 | Shared per-request timeout (per-capability defaults) |
searchTimeoutMs | number | 30000 | Search-only timeout; blank follows timeoutMs |
fetchTimeoutMs | number | 30000 | Fetch-only timeout; blank follows timeoutMs |
fetchFormat | string | markdown | Body format requested from the fetch endpoint (markdown, text, html) |
maxCharacters | number | 50000 | Character cap for fetched bodies; sent to the gateway and enforced locally |
apiKey | secret | โ | Literal API key (optional; no key = no Authorization header) |
apiKeyEnv | credential-ref | NINE_ROUTER_API_KEY | Credentials-service key name |
Self-hosted 9router picks its search and fetch backends from its own provider configuration and ignores searchModel/fetchModel; keep those fields set for cloud gateways that route by model.
Endpoint precedence โ an explicit baseURL setting wins over the NINE_ROUTER_BASE_URL environment value; with neither set, no endpoint exists and the providers report themselves unavailable. There is no silent fallback to a repository-chosen remote. The schema rejects non-http(s) URLs, empty model/format strings, and non-positive numeric limits before any request is made.
Credentials โ NINE_ROUTER_API_KEY is resolved through DSH's credentials service; a literal apiKey is optional and wins when set. apiKeyEnv is a reference name in the credentials service, not a key. The secret is write-only in the settings UI, is never stored in git, and never appears in logs, diagnostics, or error messages.
๐ DSH compatibility
| Version | |
|---|---|
| Minimum supported | 0.1.7-rc.1 (peer range >=0.1.7-rc.1 <0.3.0) |
| Latest tested | the newest published 0.2.x โ CI installs it (currently 0.2.0-rc.2) and runs the full suite against it |
CI and the release workflow both run the shared compatibility check (scripts/check-dsh-compat.mjs): once against the declared minimum and once against the latest published 0.2.x. A failing check stops the release workflow before the release is created. Versions outside the declared range โ including future 1.x releases โ are not claimed compatible until they are exercised the same way.
๐ก๏ธ 9router security
The web_fetch capability delegates URL extraction and SSRF protection to the 9router server: the plugin sends the target URL to POST /v1/web/fetch and trusts the gateway's fetch boundary. It implements no local SSRF policy of its own.
Run a patched, current 9router release โ the fetch endpoint has a published security advisory:
๐งช Development
pnpm install # install dependencies
pnpm test # run the test suite (node:test)
node scripts/validate-pack.mjs # validate the packaged artifact
Node >=20 (CI runs Node 22) and pnpm (CI uses pnpm 10).
Repository layout
dsh-9router-web-search/
โโโ src/ # server-side plugin: index.js + nine-router-client.js
โโโ client.js # settings card
โโโ cordis.patch.yml # bundle patch registering the plugin
โโโ test/ # node --test contract suite
โโโ scripts/ # validate-pack.mjs, sync-storefront.mjs
โโโ .github/workflows/ # CI (tests + packaging, DSH 0.2.x compat) and release
โโโ package.json # ESM plugin manifest
Releases โ stable versions ship as v<version> GitHub Releases matching package.json; the release workflow re-runs the full suite and packaging validation against the tag before publishing.
Storefront sync โ node scripts/sync-storefront.mjs syncs the plugin entry into the storefront repo (manual; requires push access to the configured storefront fork).
๐ฑ Ecosystem & releases
- ๐ฆ Distribution โ the GitHub repository is the only distribution source; stable versions ship as
v<version>GitHub Releases. - ๐ Issues & requests โ open an issue.
๐ License
๐ Acknowledgments
This project began as a fork of rebron1900/dsh-web-search-9router โ thank you for the original 9router-backed web search and fetch provider for DeepSeek Harness.
Comments
Loadingโฆ