# dsh-web-fetch-enhanced

Fetch half of [dsh-tool-web-enhanced-profile](../profile/README.md).
**Install the profile, not this package**: the profile mounts this package as
row `web-fetch-enhanced` and selects its provider in the shared `web` row.

| | |
| --- | --- |
| Row id | `web-fetch-enhanced` |
| Provider id in `ctx.web` | `fetch-enhanced` |
| Model surface | DSH's own `web_fetch` (tool-web), unchanged; with the row's Enhanced tools switch on, also `web_fetch_enhanced` and `list_web_fetch_providers` |
| Per conversation | one connection or Off, from the composer menu or the Host command `/setup-fetch` (Web GUI and dsh-TUI) |
| Settings | row settings page on the Plugins page (`plugins.row.config`) |

## What it does

Choose local or remote fetching per conversation from the composer menu or
`/setup-fetch`; Off hides `web_fetch` from that conversation's Agent from the
next model request step. The connections are `builtin:local` (the default:
DSH's own HTTP(S) fetcher plus an operator allowlist for non-public
addresses), DSH's DeepSeek Fetch API, Exa, Firecrawl, Tavily, Tinyfish and AnySearch,
plus custom adapter connections such as a self-hosted endpoint.

- **Remote services start off.** DeepSeek Fetch API, Exa, Firecrawl, Tavily,
  Tinyfish and AnySearch must be turned on in the row settings before a conversation can
  choose them; turning one on agrees that URLs go to it. Local HTTP (the
  default) stays on; custom connections are on when created. When every remote
  service is off, the composer menu says more services can be turned on in
  settings.
- **AnySearch takes a personal API key only** (`ANYSEARCH_API_KEY`, the same
  credential name as AnySearch's own plugin): the service has an anonymous
  tier, but this plugin does not use it. It has no options; it reads HTML,
  plain text, JSON and Markdown (not PDF or other binary files) and may cut
  long pages at 50,000 characters. Do not install it together with
  `@anysearch/anysearch-dsh`: that bundle's profile layer writes both fields
  of the `web` row as `anysearch`, so routing leaves this plugin.
- **`/setup-fetch`.** A Host command, so it works in the Web GUI and in
  dsh-TUI. `off` or a connection id changes the choice from the next model
  request; dsh-TUI completes these arguments. Without arguments the Web GUI
  opens the chooser, and dsh-TUI prints the current choice, routing and the
  enabled connections (0.16.1 shows only the start of that, as a one-line
  notice). Its description and output are English.
- **Enhanced tools (optional).** With the row's Enhanced tools switch on (off
  by default; turning it on agrees that the URL goes to the service the Agent
  picks), the Agent also gets `web_fetch_enhanced` (`url` plus a required
  `provider`, a connection id) and `list_web_fetch_providers`, which also
  shows the local allowlist. They are registered only while the `web` row
  routes fetch to this plugin, and only conversations started afterwards get
  them, limited to the connections enabled when the conversation started. An
  explicit call never changes the conversation's choice or model memory, is
  refused when the conversation turned fetch off, and runs through the same
  execution layer.

- **Who controls access.** Only local fetching applies the operator's address
  allowlist; an empty allowlist is exactly DSH's public-only fetch. Hostnames
  reached through a proxy are resolved by the proxy, so the allowlist cannot
  limit them. Remote services receive the URL as requested and own target
  access; the menu and settings page say which service receives it and what
  its terms say about caching and retention.
- **Credentials.** Keys live in DSH Credentials; settings store only the
  reference name. Adapter API keys are validated before requests; the native
  DeepSeek Fetch API connection retains DSH's credential handling.
- **Results and errors.** Remote bodies are text; without a status reported by
  the service a result is `HTTP 200` for the requested URL. Errors are a short
  message of this plugin with a `WEB_*` code, optionally followed by the
  service's own explanation marked `(untrusted)`; local fetching passes DSH's
  own errors through unchanged. Errors generated by the local connection itself
  (allowlist, DNS, cancellation, unexpected failures and rule validation) carry
  the `dsh-web-fetch-enhanced: ` prefix. There is no retry and no fallback. This request's API key
  or account token is kept out of what the model sees (withheld from error
  text, replaced by `[redacted]` in successful responses), with one known gap;
  see [known limitations](../../docs/design.md#已知限制).

See [Functional design](../../docs/design.md) for [connections](../../docs/design.md#连接与目录),
[the local allowlist](../../docs/design.md#fetch-local白名单与提示),
[remote results](../../docs/design.md#远程抓取的结果映射与上限),
[settings](../../docs/design.md#配置文档), [enhanced tools](../../docs/design.md#增强工具) and [errors](../../docs/design.md#错误与上游说明).

## Upgrading from 0.1.x

Versions up to 0.1.x were a standalone bundle that took the native `http`
seat. From 0.2.0 this package is a plain plugin of the profile bundle: remove
the 0.1.x bundles, then install the profile. Upgrading this package alone
removes its row.

0.1.x settings are not read or migrated. Calls fail with
`WEB_PROVIDER_CONFIGURED_UNAVAILABLE` and a fixed message asking the user to
repair the settings. Field diagnostics are available in the settings page and
Host log. Press **Restore default settings** (Reset) on the settings page, or
delete the fields by hand, then enter your allowlist again under
`builtin:local`. Nothing is rewritten until you do. Details:
[upgrading from 0.1.x](../../docs/design.md#从-01x-升级).

Architecture: [docs/architecture.md](../../docs/architecture.md).
