DSH plugin web seams: WebSearchRequest and WebFetchRequest
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.
- Service definition:
dsh-webownsctx.weband the provider registry. - Providers: exa, perplexity and deepseek for search; an http implementation for fetch.
- Consumer:
dsh-tool-webexclusively owns theweb_searchandweb_fetchschemas and rendering. - Swapping providers keeps the call shape: how the model submits a query or URL does not change.
- 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.
interface WebSearchRequest { query: string; maxResults?: number }
interface WebSearchResult { content?: string; sources: WebSearchSource[]; truncated: boolean }
- Fan-out: the consumer accepts a
queriesarray and splits it into separate requests; a single element is one search. - Bound origin:
maxResultsis consumer configuration (default 8) passed through unchanged. - Enforcement: over-returning providers are truncated by the seam with
truncatedset. - Optional content: some providers return a generated answer, others only sources.
- Source shape:
urlis required whiletitle,snippetandpublishedAtare optional — forcing adapters to invent them would make the seam lie. - 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.
interface WebFetchRequest { url: string }
interface WebFetchResult { url: string; statusCode: number; body: WebFetchBody; truncated: boolean }
- Why one field: timeouts and cancellation are execution arguments, while format, prompts and extraction belong to higher layers.
- Status semantics: 404 or 500 still produces a result with a bounded decoded body.
- Final URL: the result's
urlis the final address after allowed redirects. - Closed body union:
htmlortext, switched exhaustively so a new kind breaks compilation until handled. - Truncation flag:
truncatedmeans the provider capped the body. - 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.
available()discipline: credential presence or parseable configuration — network calls are forbidden.- Selection timing: read at execution time, not a background health check.
- Explicit ids:
searchProvider/fetchProviderconfiguration or matching environment variables. - Single provider: auto-selected when exactly one is available.
- Ambiguity: several available with no id throws
WEB_PROVIDER_AMBIGUOUSinstead of picking the first registered. - 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.
- Selection failures:
WEB_PROVIDER_AMBIGUOUSand similar, whose codes and messages identify missing ids or ambiguous candidates. - Fetch failures: unreachable networks, disallowed redirects, bodies that cannot be safely represented.
- Search failures: provider call failures or unparsable responses.
- Not failures: non-2xx status, truncated bodies and truncated source lists — all fields on results.
- Branching: read the kind and code first, then decide whether to retry, switch providers or explain to the user.
- 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.
- No provider — check credentials and configuration;
available()false means it will not be selected. - Ambiguity errors — configure a provider id explicitly.
- Body seems short — check
truncated; it is a cap, not a failure. - Fewer sources — the
maxResultsbound was reached and the seam truncated. - 500 not retried — non-2xx is a result; retry policy belongs to your layer.
- 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
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.
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.
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.
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.
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
- DeepSeek Harness docs — Web access (search/fetch requests, provider availability, network policy, errors)· deepseek-harness.github.io
- dsh-web source (types and provider registry)· deepseek-ai (GitHub)
- dsh-tool-web (the two model-facing tool schemas)· deepseek-ai (GitHub)