DSH web search provider selected by vendor x protocol: Chat Completions, Responses, and Anthropic Messages with built-in search tools, plus the standalone search APIs of DeepSeek, Kimi, and Zhipu; four custom targets cover gateways; UI copy follows the app language (zh, en, ja, es, fr, de, ru, pt). (Original language)
Review the source and trust level before running this DSH plugin command.
dsh-web-search-diy
English · 简体中文
<p align="center">
<a href="https://www.npmjs.com/package/dsh-web-search-diy"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-web-search-diy?style=flat-square&label=npm&color=cb3837"></a>
<a href="LICENSE"><img alt="license: MIT" src="https://img.shields.io/npm/l/dsh-web-search-diy?style=flat-square&color=blue"></a>
<a href="package.json"><img alt="node >= 18" src="https://img.shields.io/badge/node-%3E%3D18-339933?style=flat-square&logo=nodedotjs&logoColor=white"></a>
<a href="#capability-matrix"><img alt="vendors: 7" src="https://img.shields.io/badge/vendors-7-8A2BE2?style=flat-square"></a>
<a href="#capability-matrix"><img alt="protocols: 4" src="https://img.shields.io/badge/protocols-4-8A2BE2?style=flat-square"></a>
<a href="https://github.com/deepseek-ai/deepseek-harness"><img alt="dsh plugin" src="https://img.shields.io/badge/dsh-plugin-4D6BFE?style=flat-square"></a>
</p>
A web search provider plugin for the DeepSeek Harness (DSH). It supplies the built-in web_search tool per vendor × protocol: three in-protocol shapes (Chat Completions / Responses / Anthropic Messages) plus standalone search, covering DeepSeek, Kimi, Zhipu, Qwen, OpenAI, Anthropic, OpenRouter, and four custom targets. Results are normalized into structured citation sources for the calling model to ground its answer on. The plugin also ships an observability page that records every search and can backfill history from older session logs.
Capabilities
- 🧭 Vendor × protocol matrix — 17 official targets (13 full + 4 degraded) and 4 custom targets. Only combinations that really search appear in the vendor list; the rest live in a collapsed section with a reason.
- 🎛️ Three-layer configuration page — search kind → protocol → vendor. Fields come from the catalog served by the host; a blank value means the combination's default.
- 🧩 Custom targets — a template picker performs a one-shot fill (selection resets, nothing is saved); endpoint, path, request field names, and response field names are all editable.
- 🧪 Test connection — runs one real search with the staged draft (nothing saved to the configuration) and grades the result by source quality.
- 🔐 Write-only credentials — API keys are stored through the credentials service, never in the configuration file; each vendor offers its reference chain.
- 🗂️ Configuration v3 — one bucket per
vendor/protocol; v1/v2 files migrate on read and the old file is backed up as .v2.bak before the first save.
- 🪜 Thinking-effort fallback — a rejected
reasoning.effort / output_config / thinking is dropped one at a time and retried.
- 📦 Dispatcher-proof decoding — bodies are read as bytes and inflated by magic number, independent of dsh's global undici dispatcher.
- 📄 Long bodies become source summaries — standalone search writes its long body into
source.summary (capped at 2,000 characters) and skips it when the original body equals snippet; snippets are capped the same way. The model reads the summary before falling back to the snippet.
- 🚦 No credential, no tool — when the selected target cannot resolve a credential,
web_search is no longer offered to the model instead of failing after invocation.
- 📊 Built-in observability page — a first-level "Config / Observability" tab. The overview shows searches, success rate, P50/P95, average sources, summary coverage, a target ranking, success-rate/P95 trends and recent records; the records view filters by status and query, expands source details, and copies a record as JSON.
- 🗄️ Local observation store and historical import —
node:sqlite with WAL, 0600 permissions, transactional writes and a 50,000-row retention cap. Importing scans $DSH_HOME/sessions for older web_search calls and is idempotent; JSONL/CSV export and a typed-DELETE clear are available.
- 🧱 Failure classes and request timeout — HTTP statuses, network failures and local timeouts map to stable error codes;
requestTimeoutMs defaults to 25 s (60 s for test connections), and caller cancellation stays distinct from a timeout.
- 📅 Calendar ranges and page-number pagination — presets plus a month calendar for start/end dates, independently for queries and imports; records page by page number with 10/20/50/100 rows and jump-to-page.
Capability matrix
Legend: ✅ full (in-protocol search + citable sources); ◐ degraded (searches, but sources or model are limited); ✗ unsupported; ⚙ custom.
| Vendor |
Chat Completions |
Responses |
Anthropic Messages |
Standalone search |
| DeepSeek |
✗ |
◐ deepseek-v4-pro only; sources from open_page |
✅ |
✅ /v1/tools/search |
| Kimi |
✗ built-in $web_search retired |
✅ web_search + include |
✗ no server tool in the schema |
✅ /v1/tools/search |
| Zhipu |
✅ web_search tool |
✅ web_search + results[] |
✗ accepts but does not run it |
✅ /paas/v4/web_search |
| Qwen |
◐ enable_search, no sources |
✅ action.sources (url only) |
✅ needs the billing header |
✗ no standalone REST |
| OpenAI |
◐ gpt-5-search-api only |
✅ full filters / include |
✗ no such endpoint |
✗ |
| Anthropic |
✗ |
✗ |
✅ native web_search |
✗ |
| OpenRouter |
✅ openrouter:web_search |
✅ same server tool |
◐ alias, untested |
✗ |
| Custom |
⚙ template + 4 variants |
⚙ template + toolType |
⚙ template + toolType |
⚙ template + 8 mapping fields |
13 full, 4 degraded (OpenRouter Anthropic is pending), 4 custom. Eight unsupported entries exist only for the collapsed section and never create a configuration bucket.
Install
Published on npm:
dsh plugin --profile web add dsh-web-search-diy
The bundle patch performs the wiring, so no manual cordis.patch.yml edits are required:
- inserts the
web-search-diy loader entry;
- overrides the shared
web row's searchProvider to diy-search and restates fetchProvider: http (a patch replaces the whole row config);
- disables the shipped
web-search-deepseek provider.
For local development, install the checkout as a link:
dsh plugin --profile web add link:./dsh-web-search-diy
The plugin declares the @deepseek-ai/* hooks as peerDependencies. Run pnpm install once in the plugin directory before linking; the harness provides the peers at runtime.
Configuration
Configuration page
Location: Plugins → Installed plugins → the dsh-web-search-diy card (clicking the card opens this plugin's configuration page). Copy follows Settings → Language (zh, en, ja, es, fr, de, ru, pt).
- Search kind:
In-protocol search or Standalone search. Standalone has no model turn, so model and output-budget fields are hidden.
- Protocol: one of Chat Completions / Responses / Anthropic Messages in-protocol; standalone is fixed to
search.
- Vendor: only vendors available under that protocol; degraded combinations show their reason on the card; unsupported ones are collapsed for the current shape.
- Fields: blank means the catalog default (shown as the placeholder). Saving a blank deletes the key.
- Endpoint override (Anthropic protocol): the launching environment variable
DEEPSEEK_SEARCH_BASE_URL overrides the endpoint; an explicitly saved Endpoint wins over it.
- Template (custom only): a one-shot picker. The selection resets immediately, the placeholder names the last template, and the template itself is never saved. If the target already has a saved configuration, switching templates first asks for confirmation and offers Reset to saved configuration.
- Save: switching vendor/protocol counts as a pending change; saving takes effect immediately (the host re-reads the file on every search).
- API key: written through the credentials service only; blank keeps the current key.
Configuration file (v3)
$DSH_HOME/dsh-web-search-diy.json, written by the configuration page:
{
"version": 3,
"vendor": "qwen",
"protocol": "responses",
"targets": {
"qwen/responses": {
"baseURL": "https://maas.qianwenaiapi.com/compatible-mode/v1",
"apiKeyEnv": "QWEN_TOKEN_PLAN_API_KEY",
"model": "qwen3.8-flash",
"maxOutputTokens": 4096,
"toolType": "web_search",
"includeSources": true
},
"custom/search": {
"baseURL": "https://search-gateway.example.com",
"path": "/v1/tools/search",
"apiKeyEnv": "SEARCH_GATEWAY_API_KEY",
"queryField": "q",
"countField": "size",
"resultsPath": "data.items",
"urlField": "link",
"titleField": "name",
"snippetField": "desc",
"count": 10
}
}
}
- The top level stores only the current
vendor and protocol; each target bucket stores only the keys declared in its fields.
- A blank value deletes the key and restores the catalog default.
template is a fill action, not configuration; submitting it is rejected.
- API keys never appear in this file.
Migrating from 1.x
v2 mode |
v3 target |
responses |
qwen/responses |
anthropic-messages |
deepseek/anthropic-messages |
zhipu-web-search |
zhipu/search |
zhipu-chat-search |
zhipu/chat-completions |
- A v1 flat object is first projected onto its mode, then migrated by the table above.
- Migration happens in memory on read; the first save writes v3 and backs the original up as
dsh-web-search-diy.json.v2.bak (once, for rollback).
- Old key names:
responsesToolType → toolType, responsesIncludeSources → includeSources, responsesReasoningEffort → reasoningEffort, anthropicThinking → thinking, anthropicEffort → effort; apiVersion is dropped (fixed at 2023-06-01).
- 2.0 registers no settings section; configuration comes from the file and the credential surface only.
Field reference
| Protocol / vendor |
Fields |
| Common |
baseURL, apiKeyEnv, model, maxOutputTokens (the last two are hidden for standalone) |
| Responses · OpenAI |
toolType, includeSources, reasoningEffort, searchContextSize, allowedDomains, blockedDomains, userLocation, externalWebAccess, returnTokenBudget, searchContentTypes, imageMaxResults, imageCaption |
| Responses · Kimi |
toolType, includeSources, allowedDomains (blockedDomains / search_context_size return 400) |
| Responses · Zhipu / Qwen |
toolType, includeSources, reasoningEffort |
| Responses · DeepSeek |
toolType; the model is locked to deepseek-v4-pro and include is not sent |
| Responses · OpenRouter |
toolType, includeSources, engine, mode, maxResults, maxUses, maxTotalResults, searchContextSize, maxCharacters, userLocation, allowedDomains, excludedDomains, xSearch |
| Anthropic Messages |
toolType, maxUses, thinking, effort, allowedDomains, blockedDomains, userLocation, responseInclusion |
| Chat · Zhipu |
searchEngine, count, searchRecencyFilter, contentSize, searchDomainFilter, requireSearch, searchPrompt, reasoningEffort |
| Chat · Qwen |
searchStrategy, forcedSearch, freshness, assignedSiteList, searchExtension, promptIntervene |
| Chat · OpenRouter |
engine, mode, maxResults, maxUses, maxTotalResults, searchContextSize, maxCharacters, userLocation, allowedDomains, excludedDomains, xSearch |
| Chat · OpenAI |
no search parameters; the model is locked to gpt-5-search-api |
| Standalone |
count, includeContent, searchEngine / contentSize / searchRecencyFilter / searchDomainFilter (Zhipu), oriQuestion / localization (DeepSeek), timeoutSeconds (Kimi), digestEntries, digestSnippetChars; custom adds path and the 8 mapping fields |
oriQuestion sends the human prompt that triggered the search as DeepSeek's ori_question: whitespace collapsed, cut to 128 characters, read from the initiating Session and omitted out
README excerpt; see the original.
DCommunity
Cyberpunk 2077 / Night City theme for the DeepSeek Harness Web UI — NC yellow × neon cyan identity, CRT scanlines, Kiroshi hover lock-on, combat-state HUD, synthesized typewriter & message SFX, boot glitch, Relic interference, slang chips, and hidden easter eggs (try sending: relic / johnny).
ACommunity
DeepSeek Harness-native integration for agent-vision-toolkit: image Q&A, OCR, grounding, UI restoration, pixel diff, Artifacts, and Web UI.
NCommunity
Sandbox-first automatic permission policy for DeepSeek Harness
LCommunity
DeepSeek Harness bridge for the full local-shell-mcp tool surface and per-session Live Workspace.
NCommunity
AgentTeams for DeepSeek Harness: multi-agent team collaboration (captain, members, tasks with dependencies, messaging) driven by natural language, with a tree monitor in the web GUI
MCommunity
Unofficial DeepSeek Harness LLM provider plugin for Command Code, ported from pi-commandcode-provider (MIT). Registers the 'commandcode' provider route with a Models-page card and live model catalog.