dsh-web-search-serper
English | 中文
Overview
@dingpenghui/dsh-web-search-serper is a web search provider plugin backed by the Serper.dev API, for the current DeepSeek Harness (DSH) web capability seam (ctx.web, @deepseek-ai/dsh-web 0.2.0-rc.x).
Serper.dev is an official Google Search partner providing fast, structured Google search results API. Free tier: 2,500 queries per month, no credit card required.
Features
- 🚀 Fast Search — 1-2 second response times using Google's real index
- 📊 Structured Results — JSON format, easy to parse
- 🔒 Privacy Friendly — No user tracking, no cookie collection
- 💰 Generous Free Tier — 2,500 monthly queries at no cost
- 🌍 Multi-language Support — Results from countries/regions worldwide
- 🔧 Takes Over Out of the Box — installing it as a bundle claims
web.searchProvider automatically; key resolved lazily per search (config → env → credential store), no restart on change
- 🛟 Automatic Fallback — when Serper is unavailable it hands the request to another usable search provider instead of breaking
web_search entirely
Quick Start
Install
# Option 1 — install from npm (recommended)
dsh plugin --profile web add @dingpenghui/dsh-web-search-serper
# Option 2 — local bundle via link:
# 1. Add to the profile's package.json `dependencies`:
# "@dingpenghui/dsh-web-search-serper": "link:<absolute path to this dir>"
# 2. Add "@dingpenghui/dsh-web-search-serper" to `dsh.profile.bundles`,
# and add the insert row to cordis.patch.yml (or copy this package's
# own cordis.patch.yml content)
pnpm install
pnpm run build
Configure
Installing as a bundle (recommended) needs no manual configuration. The
package's own cordis.patch.yml is applied with the bundle and claims the web
seam's search provider for serper:
- id: web
name: '@deepseek-ai/dsh-web'
config:
searchProvider: serper # overrides dsh-base's deepseek-official
fetchProvider: http # must be restated: a patch replaces the whole config
- insert:
- id: web-search-serper
name: '@dingpenghui/dsh-web-search-serper'
Why the takeover is required. dsh-base pins web.searchProvider to
deepseek-official, and the seam's selection rule is "a configured id is the
only candidate — never a fallback on failure". Inserting the row without the
takeover leaves the plugin registered but never invoked, and silently so.
Your profile's own cordis.patch.yml is applied after the bundle layer and
wins, so overriding - id: web there switches to another backend.
If you are not using the bundle mechanism and copy rows into your profile patch
by hand, copy both blocks above — otherwise it will not take effect either.
No config is required: the API key is resolved lazily per search in this order:
- row
config.apiKey (explicit, when you add a config block to the row — editable on the plugin detail page, hot-applied after save);
- the
SERPER_API_KEY environment variable of the DSH host process;
- a
SERPER_API_KEY reference in the DSH credential store
($DSH_HOME/.credentials.yaml refs: — resolved per search, no restart on change).
To pin the key and options in the composition instead:
- id: web-search-serper
name: '@dingpenghui/dsh-web-search-serper'
config:
apiKey: your-serper-api-key
gl: cn # Optional: set default country code
Behavior: Serper first, automatic fallback
- Preferred — whenever Serper is ready (key present, endpoint valid) it is used;
- Fallback — if Serper fails for any reason (missing key, 401/403 auth
failure, 429 rate limit, 5xx, network error, misconfigured endpoint, …), the
request is handed to another registered and usable search provider on the
seam, normally the
deepseek-official provider shipped with dsh-base;
- Not on cancel — a user cancellation (
WEB_ABORTED) never falls back;
- Both down — throws
WEB_PROVIDER_ERROR whose message names both the
primary and the fallback failure, with the fallback error on the cause chain.
The fallback lives inside the plugin, because the DSH web seam itself does
not fall back (a configured id is the only candidate). Accordingly,
available() still returns true when Serper is unusable but a fallback target
exists — otherwise the seam would reject the provider with
WEB_PROVIDER_CONFIGURED_UNAVAILABLE before search() ever ran, and no
fallback could happen.
Get API Key
- Visit https://serper.dev
- Register for a free account
- Get your API Key from the Dashboard
- Free tier: 2,500 queries per month
Configuration Options
| Field | Type | Required | Default | Description |
|---|
apiKey | string | No | $SERPER_API_KEY, then credential reference SERPER_API_KEY | Serper API key (secret, volatile) |
baseURL | string | No | https://google.serper.dev | API endpoint base |
gl | string | No | - | Country code (e.g., us, cn, jp) |
cr | string | No | - | Region code (e.g., us; sent as the cr parameter) |
numResults | number | No | omitted (Serper defaults to 10) | Default result count, capped at 100 |
Usage Examples
Basic Search
import { apply } from '@dingpenghui/dsh-web-search-serper'
// Used by the Cordis loader; no direct calls needed in most deployments.
// In a Cordis plugin:
// apply(ctx)
Search via ctx.web
const result = await ctx.web.search({
query: 'latest AI developments 2026',
maxResults: 5,
})
console.log(result.sources)
// [
// { url: '...', title: '...', snippet: '...' },
// ...
// ]
Error Handling
| Error Code | Meaning | Resolution |
|---|
WEB_PROVIDER_CONFIGURED_MISSING | Configured provider not registered | Check if plugin is loaded correctly |
WEB_PROVIDER_CONFIGURED_UNAVAILABLE | Provider registered but no key available | Check API key: config / $SERPER_API_KEY / credential reference |
WEB_ABORTED | Request was aborted | Check AbortSignal |
WEB_PROVIDER_ERROR | API request failed | Check network / API key / rate limits |
WEB_PROVIDER_CONFIGURED_UNAVAILABLE and WEB_PROVIDER_ERROR only reach
web_search when the fallback target is unusable too; a Serper-only
failure is absorbed by the automatic fallback (see "Behavior" above).
Limitations & Known Issues
- Free tier limit — 2,500 monthly queries, paid plans for higher usage
- Google Search only — Does not support Bing, Baidu, or other search engines
- No generated answers — Returns search results only, no AI-generated summaries
- API Key required — Must provide a valid Serper API Key via config, environment, or credential reference
Related Projects
License
MIT License — See LICENSE file