Files
deepseek-harness/packages/web/tool-web
Tianyi Cui ecb8aa5b8e Add a gated Known Limitations and Deferred Work section to every package README
Every packages/*/* README now carries a canonical '## Known Limitations and
Deferred Work' section: condensed, evidence-backed bullets for consumer-visible
gaps (unimplemented features, platform caveats, MVP cuts) and consciously
postponed work (TODO/FIXME/XXX markers, RFC deferrals still open). The ten
pre-existing ad-hoc variants ('What is NOT here (TODO)', 'Deferred',
'Limitations (MVP)', 'Known limitations (tracked TODOs)', ...) are normalized
into the canonical heading.

A new doc-sync gate, scripts/verify-readme-limitations.ts, enforces the shape:
exactly one limitations-like heading per package README, byte-equal to the
canonical h2, with at least one bullet; near-miss headings fail so variants
cannot creep back. Packages with genuinely nothing to declare (dsh-brand,
dsh-timeout, dsh-subagent-mock, dsh-app-boot) are whitelisted in the script and
must NOT carry the section; whitelist entries are validated against the scanned
package set so a rename fails loud.

Wired into the doc-sync chain (package.json) and the run-gates doc-sync leaf
set; the standing rule lands in packages/AGENTS.md and the adding-a-package
cookbook; decision record in
docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md
(RFC index regenerated).

Also fixes two stale '(deferred)' markers claiming dsh-compact-basic is
unimplemented (the dsh-compact seam README's package table and the seam's
module doc comment).
2026-07-12 01:46:34 +08:00
..

@deepseek-ai/dsh-tool-web

The model-facing web tool suite — web_search and web_fetch — over the web capability seam (ctx.web). It owns model-facing concerns only: tool names, JSON schemas, snake_case argument names, prompt sections, the result-count bound, result formatting, HTML→markdown presentation, and presentCall. All web access goes through ctx.web; this package never imports a concrete provider. Neither tool exposes a model-facing timeout — each tool's cooperative tool-call budget is declared here via config (fetchTimeoutMs/searchTimeoutMs, attached as ToolDefinition.timeoutMs) and enforced by @deepseek-ai/dsh-timeout-policy (a tools/execute wrapper); each tool just forwards exec.signal to the seam.

Each tool is registered independently; a product that wants only one disables the other via config ({ search: false } / { fetch: false }).

Tools

Tool Args Behavior
web_search query (string) Discovery. Returns an optional answer plus source URLs. max_results is not model-facing — the tool sets the bound (the searchMaxResults config, default 8) and passes it to the seam.
web_fetch url (string) Retrieves a specific URL. HTML bodies are rendered to markdown-ish text; text bodies pass through. A non-2xx status is reported, not an error. The tool-call timeout is deployment policy (dsh-timeout-policy), not a model argument.

Config

Key Default Meaning
search true Register web_search.
fetch true Register web_fetch.
searchMaxResults 8 Upper bound on sources returned by one web_search call (the seam truncates a longer provider list and flags it).
fetchTimeoutMs 30000 Cooperative tool-call timeout budget (ms) for web_fetch.
searchTimeoutMs 30000 Cooperative tool-call timeout budget (ms) for web_search.

fetchTimeoutMs/searchTimeoutMs declare each tool's cooperative timeout budget (attached as ToolDefinition.timeoutMs), enforced by @deepseek-ai/dsh-timeout-policy; the model-facing schema exposes no timeout argument.

- id: tool-web
  name: '@deepseek-ai/dsh-tool-web'

Stable registration

Tool registration follows product enablement, not backend availability. A tool stays visible even when its selected provider is missing, misconfigured, ambiguous, or temporarily unavailable; the seam resolves the provider at execution time and execution fails with a structured WebError (e.g. WEB_PROVIDER_UNAVAILABLE, WEB_PROVIDER_AMBIGUOUS), which ToolRegistry.execute() turns into an error tool result the model can read and hooks/UI can route on. This keeps the model schema stable without making plugin load order, credential state, or HMR timing part of the model-facing contract. To remove a web tool entirely, disable it here in config.

The tool never calls a provider's status() and never enumerates providers — its only execution path is ctx.web.search() / ctx.web.fetch(), and provider unavailability reaches it as the structured WebError codes selection throws at execution time. Provider selection stays entirely inside the seam, with one owner.

Known Limitations and Deferred Work

  • htmlToMarkdown is a minimal regex converter, not an HTML parser — it strips script/style/noscript, keeps headings/bullets/links, and decodes about a dozen named entities; tables, images, and nested formatting are lost.
  • The model-facing surface is minimal by design, with promotions deferredmax_results stays a config bound (not a model argument), and web_fetch takes only url (no format/prompt/LLM-summarization mode); both are named later steps in the seam RFC.
  • No permission gating — both tools execute without any permission prompt or policy; integration awaits the deferred permission system, with the owner (a tools/execute plugin, provider config, or both) undecided.