dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
把内置 web_fetch 工具的抓取后端换成 Decodo Web Data API:默认返回 Markdown,并把 fetchProvider 固定为 decodo,可配置单进程抓取上限;需要 Decodo API Key,web_search 不受影响。
A web fetch plugin for DeepSeek Harness (dsh) that routes the agent's built-in web_fetch tool through the Decodo Web Scraping API to retrieve content from sites that block anonymous requests.
Install the plugin and the agent keeps calling web_fetch as usual. Decodo retrieves the page and returns readable content, with Markdown by default. You don't need to add a new agent tool or change its prompts.
403 or bot challenge to a direct request, including retail, real estate, and job listings.Create a Decodo account to start a free plan with up to 2K requests. No credit card required.
DeepSeek Harness exposes a built-in web_fetch tool with a provider seam behind it. The plugin registers Decodo at that seam and pins it as the fetch provider for the profile where you install it.
The agent still calls web_fetch with the same name and schema, and receives the same tool output format. The retrieval happens through Decodo rather than a direct request from the DeepSeek Harness process. The plugin does not replace web_search.
A direct fetch may receive a 403 or a bot challenge. For AI agent web scraping, Decodo handles retrieval with anti-bot and CAPTCHA handling to help bypass bot detection where possible. Success still depends on the target page.
Use this plugin when your agent needs to read the web as it actually is:
The plugin gives the agent an API-backed fetch provider without requiring you to configure a separate web scraping proxy. Fetching uses Decodo; search remains with your profile's existing search provider.
Every fetch goes through Decodo, with no tool selection. The agent does not choose a scraping tool or learn a new one. It calls web_fetch as it always did.
Markdown by default. The API returns Decodo's Markdown and the plugin hands it to the model untouched. When conversion isn't possible, the raw HTML comes back and DeepSeek Harness converts it, so the model always gets readable text.
An explicit provider pin. The bundle patch pins fetchProvider: decodo rather than relying on being the only provider mounted, so it keeps working when other providers are mounted.
A fetch limit. A configurable per-process ceiling on requests, with a clear error to the model when it is reached. Agent loops are the main bill-shock risk.
Errors the model can act on. Auth, rate limit, validation, timeout, and scrape failures each map to a distinct code with a single-line message.
Install with the dsh CLI. The package ships a DeepSeek Harness bundle patch, so dsh plugin --profile <name> add wires everything up with no config file to edit.
pnpm add -g @deepseek-ai/dsh
dsh plugin --profile headless add @decodo/dsh-web-fetch
export DECODO_API_KEY='your-api-key'
dsh --profile headless "Fetch https://www.zillow.com/ and tell me the first heading"
Use pnpm for this DeepSeek Harness install. The dsh CLI plugin manager forwards to pnpm.
pnpm add -g @deepseek-ai/dsh
dsh plugin --profile <name> add @decodo/dsh-web-fetch
<name> is the dsh profile you use, for example headless for one-shot runs or web for the browser UI. Install into each profile you want covered.
That's the whole install. The package ships a bundle patch that dsh inserts into the profile's layer stack, so there is no cordis.patch.yml to edit by hand.
Copy your Web Data API key from the Playground and export it before starting DeepSeek Harness:
export DECODO_API_KEY='your-api-key'
Older plans only have a basic authentication token. Export it as SCRAPER_API_TOKEN instead. If both are set, the API key is used.
dsh --profile <name> --dump-config | grep -A4 -E '^- id: (web|tool-web|web-fetch-decodo)$'
You should see fetch: true, fetchProvider: decodo, and the web-fetch-decodo row. Then ask the agent to fetch a page:
dsh --profile headless "Fetch https://www.zillow.com/ and report the status and first heading"
Check that the tool returns a status and page content. The response may vary by site and time; an HTTP 200 alone does not establish which provider handled the fetch, so also check the pinned provider in --dump-config.
Installing this plugin is your explicit choice to enable web_fetch. The bundle patch:
tool-web to fetch: true with a 60s fetchTimeoutMs, since dsh's default of 30s is short for protected sites,web.fetchProvider: decodo so this provider wins even when the built-in http provider is mounted,web-fetch-decodo row with the config below.dsh keeps its built-in http provider mounted. To switch back without uninstalling, add or update the web row in your profile's cordis.patch.yml:
- id: web
config:
searchProvider: deepseek-official
fetchProvider: http
This example assumes your current search provider is deepseek-official. If it differs, use your existing searchProvider value. The patch replaces the row's entire config, so carry over any other settings you want to keep. You can check the current values with dsh --profile <name> --dump-config.
Override in your profile's cordis.patch.yml. A patch replaces the row's whole config, so restate every field you want to keep.
- id: web-fetch-decodo
config:
apiKeyEnv: DECODO_API_KEY # env var holding the Web Data API key
tokenEnv: SCRAPER_API_TOKEN # env var holding the basic auth token (older plans)
output: markdown # markdown (default) or html
maxFetchesPerSession: 200 # fetch limit per dsh process; 0 disables
maxContentChars: 200000 # body cap; longer bodies are cut and flagged truncated
requestTimeoutMs: 60000 # request timeout, keep at or below the tool's fetchTimeoutMs
| Field | Default | Meaning |
|---|---|---|
apiKeyEnv | DECODO_API_KEY | Env var holding the Web Data API key; sent as Bearer auth. Takes precedence over the token |
tokenEnv | SCRAPER_API_TOKEN | Env var holding the basic auth token for older plans; sent as Basic Auth |
output | markdown | markdown for Decodo's Markdown, html for the raw page |
maxFetchesPerSession | 200 | Requests allowed per dsh process; 0 disables the cap |
maxContentChars | 200000 | Body cap; longer bodies are cut and flagged truncated |
requestTimeoutMs | 60000 | Request timeout |
With output: markdown, the plugin requests Markdown from Decodo. When conversion succeeds, the plugin passes the result to the model unchanged. If the page is too large or empty, or if conversion fails, Decodo returns raw HTML with a note. DeepSeek Harness then converts the HTML. With output: html, Decodo always returns raw HTML for DeepSeek Harness to convert.
Every fetch counts against maxFetchesPerSession, including attempts that fail. Past the cap, the tool returns an error naming the setting and makes no further API calls until dsh restarts or the cap is raised.
The counter is per dsh process, so in a long-lived profile such as web, it may span multiple chats.
Failures reach the model as Error: <message> with a machine-readable code.
| Code | Cause |
|---|---|
DECODO_TOKEN_MISSING | No credential is configured |
DECODO_AUTH_FAILED | Credential rejected (401/403) |
DECODO_RATE_LIMITED | Rate limit reached (429) |
DECODO_INVALID_REQUEST | Request rejected (400/422), for example, because the URL is unsupported |
DECODO_SCRAPE_FAILED | Scrape failed or the API returned an error |
DECODO_FETCH_CAP_REACHED | Fetch limit hit |
DECODO_BAD_RESPONSE | Response couldn't be read |
WEB_INVALID_URL | Not an http(s) URL |
WEB_ABORTED / WEB_FETCH_TIMEOUT | Cancelled or timed out |
WEB_PROVIDER_ERROR | Couldn't reach the API |
A page that answers with a non-2xx status is a result, not an error. The model sees Fetched <url> (HTTP <status>) and whatever body came back, matching dsh's provider contract.
x-integration: dsh header so Decodo can attribute traffic to this plugin, the same way the Decodo CLI and MCP server tag theirs.maxFetchesPerSession limit, including failed attempts. Only successful scrapes count toward your Decodo plan's usage.configured web provider "decodo" is registered but unavailable
No credential is set. Export DECODO_API_KEY (or SCRAPER_API_TOKEN on older plans) in the environment where dsh runs.
configured web provider "decodo" is not registered
The plugin isn't installed in the profile you're booting. Run dsh plugin --profile <name> add @decodo/dsh-web-fetch and check with --dump-config.
Decodo authentication failed
Check your API key (or basic auth token on older plans) in the Playground and confirm that DECODO_API_KEY (or SCRAPER_API_TOKEN) is exported in the environment where DeepSeek Harness runs.
The agent says the page was empty
Check the status in the tool output. A non-2xx status is reported as a result, so the model sees what the site returned.
Tool calls time out
Raise fetchTimeoutMs on the tool-web row and keep requestTimeoutMs at or below it.
corepack enable if needed)git clone https://github.com/Decodo/dsh-web-fetch
cd dsh-web-fetch
pnpm install
pnpm build
pnpm typecheck
pnpm test # unit tests, no network
pnpm test:e2e # requires credentials; see e2e/README.md
pnpm dev:setup # installs dsh under dev/, links this repo into the profiles
pnpm dev "say hi and list your tools" # one-shot headless run
pnpm dev:web # browser UI at http://127.0.0.1:3080
dev/dsh.sh reads the credential from the environment and falls back to the Decodo CLI API key or token in ~/.config/decodo/config.json. The model comes from dev/model.patch.yml, an OpenAI-compatible route configured by TEST_GATEWAY_URL, TEST_API_KEY, and TEST_MODEL; any chat-completions endpoint works. The plugin is linked and the wrapper rebuilds before each run, so edits to src/provider.ts apply on the next run.
The HTTP layer is @decodo/sdk-ts. It owns the endpoint, the auth header, the x-integration header, request validation, and the error classes the plugin maps onto dsh's WebError codes. The one thing the SDK cannot do is accept an external AbortSignal, so the plugin races the SDK call against dsh's signal: the tool call fails promptly on abort or timeout while the underlying request runs on until requestTimeoutMs. Keep that value at or below the tool's fetchTimeoutMs.
@deepseek-ai/dsh-web is a peer dependency for WebError and the provider types.
.github/branch-ruleset.json mirrors the ruleset on main: pull requests only, one approval, squash merges only, CI and the PR title check required, no force pushes or branch deletion. To apply changes to it:
id=$(gh api repos/Decodo/dsh-web-fetch/rulesets --jq '.[] | select(.name == "dsh-web-fetch-main") | .id')
gh api "repos/Decodo/dsh-web-fetch/rulesets/$id" -X PUT --input .github/branch-ruleset.json
Releases are automated. Merging to main publishes a new version based on the
PR title, which must follow Conventional Commits:
fix: → patch, feat: → minor, feat!: or a BREAKING CHANGE: footer → major.
chore:, docs:, ci:, refactor:, test: don't release. Don't edit the
version in package.json.
DeepSeek Harness plugins can provide different backends for the same web_fetch tool. Choose according to how you want pages retrieved:
| Provider | Retrieval approach |
|---|---|
| Decodo (this plugin) | Decodo's hosted Web Scraping API, with an API key or basic auth token and request-based usage |
dsh-web-fetch-playwright | A local Playwright browser or an existing browser over CDP |
dsh-web-fetch-crw | Your self-hosted crw service through its Firecrawl-compatible API |
These are separate fetch providers with their own setup and behavior. Review their documentation for current requirements.
Install the plugin and let your dsh agent fetch pages through Decodo.
Start scraping for free | Web Scraping API documentation | Discord
All code is released under the MIT License.