DSH plugin web seams: WebSearchRequest and WebFetchRequest

Plugin DevelopmentPublished 2026-10-17Author: DeepSeek Plugin Market
DeepSeek HarnessDSH pluginWebSearchRequestWebFetchRequestWebErrorprovider
How to write a DSH plugin web provider: one ctx.web for search and fetch, consumer-set bounds, non-2xx results, and order-free selection.

The DSH plugin web seam keeps search and fetch on one ctx.web, but not to share request shapes — the two do not even share a schema. What they share is middleware: a single owner of provider selection, one abort and error vocabulary, and one product configuration surface. The cost is parallel searchX/fetchX method pairs, which the docs call intentional. When writing a provider, two rules matter: maxResults is consumer-set and enforced by the seam on the way back, and non-2xx is a result, not an error.

DSH plugin web seam layers: definition, providers, one consumer

Bottom line: providers register capabilities, not tools; tool names, schemas, prompts and rendering live in the single consumer.

  1. Service definition: dsh-web owns ctx.web and the provider registry.
  2. Providers: exa, perplexity and deepseek for search; an http implementation for fetch.
  3. Consumer: dsh-tool-web exclusively owns the web_search and web_fetch schemas and rendering.
  4. Swapping providers keeps the call shape: how the model submits a query or URL does not change.
  5. Optional capability: outside the agent loop mainline, with its vocabulary defined here rather than in core.

DSH plugin WebSearchRequest: one query, one bound

Bottom line: a seam request carries one query; the consumer sets the bound and the seam truncates on return.

ts
interface WebSearchRequest { query: string; maxResults?: number }
interface WebSearchResult { content?: string; sources: WebSearchSource[]; truncated: boolean }
  1. Fan-out: the consumer accepts a queries array and splits it into separate requests; a single element is one search.
  2. Bound origin: maxResults is consumer configuration (default 8) passed through unchanged.
  3. Enforcement: over-returning providers are truncated by the seam with truncated set.
  4. Optional content: some providers return a generated answer, others only sources.
  5. Source shape: url is required while title, snippet and publishedAt are optional — forcing adapters to invent them would make the seam lie.
  6. Display fallback: the consumer renders title ?? hostname(url).

DSH plugin WebFetchRequest: URL only, status is resource state

Bottom line: the request deliberately carries only a URL; non-2xx still returns a result and WebError is reserved for unsafe retrieval.

ts
interface WebFetchRequest { url: string }
interface WebFetchResult { url: string; statusCode: number; body: WebFetchBody; truncated: boolean }
  1. Why one field: timeouts and cancellation are execution arguments, while format, prompts and extraction belong to higher layers.
  2. Status semantics: 404 or 500 still produces a result with a bounded decoded body.
  3. Final URL: the result's url is the final address after allowed redirects.
  4. Closed body union: html or text, switched exhaustively so a new kind breaks compilation until handled.
  5. Truncation flag: truncated means the provider capped the body.
  6. Safety boundary: redirect and protocol limits belong to the fetch network policy; do not relax them inside a provider.

DSH plugin provider availability and selection: order-free

Bottom line: available() is a local check only; selection uses an explicit id or a single available provider, and ambiguity throws.

  1. available() discipline: credential presence or parseable configuration — network calls are forbidden.
  2. Selection timing: read at execution time, not a background health check.
  3. Explicit ids: searchProvider / fetchProvider configuration or matching environment variables.
  4. Single provider: auto-selected when exactly one is available.
  5. Ambiguity: several available with no id throws WEB_PROVIDER_AMBIGUOUS instead of picking the first registered.
  6. Order independence: registration, configuration and HMR order never participate.

DSH plugin web error classification: what actually fails

Bottom line: failure means the resource cannot be safely retrieved or represented; status code plus body is a result.

  1. Selection failures: WEB_PROVIDER_AMBIGUOUS and similar, whose codes and messages identify missing ids or ambiguous candidates.
  2. Fetch failures: unreachable networks, disallowed redirects, bodies that cannot be safely represented.
  3. Search failures: provider call failures or unparsable responses.
  4. Not failures: non-2xx status, truncated bodies and truncated source lists — all fields on results.
  5. Branching: read the kind and code first, then decide whether to retry, switch providers or explain to the user.
  6. Verify: request a 404 page on purpose and expect a result with statusCode: 404, not an exception.

DSH plugin web provider troubleshooting

Bottom line: separate no provider, blocked by policy and truncated results.

  1. No provider — check credentials and configuration; available() false means it will not be selected.
  2. Ambiguity errors — configure a provider id explicitly.
  3. Body seems short — check truncated; it is a cap, not a failure.
  4. Fewer sources — the maxResults bound was reached and the seam truncated.
  5. 500 not retried — non-2xx is a result; retry policy belongs to your layer.
  6. Repair status, stated honestly: the shared middleware rationale, request/result shapes, availability and selection rules follow the official Web access page; check network policy and signatures against that page and its Cordis API.

Sources: Web access, dsh-web source, dsh-tool-web.

FAQ

Why does DSH plugin web access use one ctx.web for both search and fetch?

DSH plugin search and fetch share one middleware layer: a single owner of provider selection, one abort and error vocabulary, and one product configuration surface. The cost is parallel searchX and fetchX method pairs, which is intentional.

When a DSH plugin search returns too many sources, who truncates them?

The DSH plugin maxResults bound is consumer-owned and passed through the seam, then enforced on the way back. A provider returning extras is truncated by the seam with truncated set, and providers may also cap at their own API layer to save cost.

Is a 404 or 500 from a DSH plugin fetch treated as a WebError?

No: DSH plugin fetch treats HTTP status as part of the fetched resource state, so non-2xx still yields a result with the status code and a bounded body. WebError is reserved for failures to safely retrieve or represent the resource.

What happens when two DSH plugin search providers are both available?

DSH plugin selection never depends on registration order: an explicit provider id is used, a single available provider is auto-selected, and multiple available providers without an id throw WEB_PROVIDER_AMBIGUOUS. It never picks whichever registered first.

May a DSH plugin provider's available() make a network health check?

No: DSH plugin available() must be a cheap local check such as credential presence or parseable configuration, and network calls are forbidden. It is an input to execution-time selection, not a health-check system.

Related Terms

WebSearchRequest
WebSearchRequest is a single DSH plugin web search request carrying one query and an optional maxResults bound. Consumers fan multiple queries out into separate requests.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/web
WebFetchResult
WebFetchResult is one fetch outcome containing the final URL after allowed redirects, the HTTP status code, the decoded body classified by kind and a truncation flag. Non-2xx responses are results, not errors.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/web
WebError
WebError is the structured error of the DSH plugin web seam, reserved for cases where a resource cannot be safely retrieved or represented, and carries codes such as provider ambiguity.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/web
WEB_PROVIDER_AMBIGUOUS
WEB_PROVIDER_AMBIGUOUS is the selection failure code raised when several providers are available and no explicit id is configured. It prevents selection from degenerating into whichever registered first.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/web

Sources