viztor/dsh-tinyfish ↗★ 1

dsh-tinyfish

TinyFish-backed search and fetch providers for the DeepSeek Harness web capability seam (ctx.web) — $0 SERP and page extraction, direct or via Monid. 适合需要零成本($0)为DSH Agent引入实时联网搜索与网页抓取能力的用户。

パッケージ
dsh-tinyfish
互換性
未検証
Harness ピア範囲
^0.2.0-rc.1
Cordis ピア範囲
~4.0.4
バージョン
0.6.3
ライセンス
MIT
最終更新
2026/10/02

インストール

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:viztor/dsh-tinyfish

ドキュメント

README 全文を読む ↗

TinyFish logo

dsh-tinyfish

Free web search and fetch for the DeepSeek Harness. Give your agent the live web — at $0 per call.

npm downloads ci license


Your agent can already reason. This gives it something to reason about: live search results and clean page content, wired straight into the harness's own web_search and web_fetch tools. Powered by TinyFish — both endpoints are free, so the web path on your host stops costing money per call.

BeforeAfter
Search bills per call$0, forever
Fetched pages arrive as HTML, converted clumsilyClean Markdown, straight from a browser-grade extractor
Switching providers means reinstallingTwo words in a config file, no reinstall

🚀 Quick start

Method 1: Direct from Web UI (Recommended)

DeepSeek Harness allows installing plugins directly through the Web interface without touching a terminal:

  1. Open DSH Web → Settings → Plugins (设置 → 插件).
  2. Click Install Plugin (添加插件).
  3. Search or enter dsh-tinyfish (or @viztor/dsh-tinyfish).
  4. Click Install — DSH automatically fetches the package from npm, builds the bundle patch, and activates it live without restarting!
  5. In Settings → Plugins → TinyFish, select your channel (direct or monid), enter your API key, and hit Save!

Method 2: Terminal / Profile package.json

For headless environments, servers, or version-controlled dotfiles:

cd ~/.dsh/profiles/web
npm install dsh-tinyfish   # or: npm install @viztor/dsh-tinyfish — same thing

Pick one name and install it once. Both tarballs carry byte-identical code and read the same settings (providers register as tinyfish, configuration lives under the row id dsh-tinyfish, credentials under the same two refs) — so switching names later loses nothing, but mounting both loads the bundle twice. dsh-tinyfish is the name DSH convention and these docs use.

📦 Installing from GitHub Packages instead

Every release mirrors @viztor/dsh-tinyfish to GitHub Packages — a second source if npmjs.org is unreachable, and what populates the repository sidebar. Only the scoped name mirrors: GitHub links packages to repositories by owner scope. Unlike npmjs, GitHub Packages requires authentication even for public packages: an unauthenticated request 404s without saying whether the package exists. With a token carrying read:packages:

# project-local .npmrc is better than global for a token
@viztor:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=ghp_xxx

then npm install @viztor/dsh-tinyfish resolves from the mirror. Unless npmjs is down, prefer it: no token, no extra configuration.

Mount it — add to that profile's package.json, then restart DSH:

{
  "dependencies": { "dsh-tinyfish": "^0.5.0" },
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        "@deepseek-ai/dsh-web-app",
        "dsh-tinyfish",
      ],
    },
  },
}

Bundles resolve at boot, so a restart picks it up — reloading the patch alone won't.

Add a key — pick a channel below, save the key, and ask your agent to search for something. That's the whole install.

🔑 Two channels, one plugin

Direct (default)Via Monid
What's behind itTinyFish's own APIThe same TinyFish endpoints, through your Monid wallet
You needA free key from tinyfish.aiA platform key from app.monid.ai
Fastest setuptinyfish auth loginmonid keys add
Costs$0$0

The default is direct, because the package is named for TinyFish — a fresh install asks for the credential its own name implies. Prefer Monid (it reuses a platform key your Monid MCP mount may already hold)? Pin it in your profile patch:

- id: dsh-tinyfish
  config:
    channel: monid

Both keys can live side by side — saving one never overwrites the other, and switching channels loses nothing.

⚙️ Settings page

Settings → Plugins → TinyFish. Everything editable lives here: the channel picker, your keys, what the search ranks on, retries, and the search/fetch toggles. Changes stage and save together; a key you type is stored by the harness, never in your profile.

The page shows the key for the selected channel, plus the saved-or-not status of both — so you always know where you stand without switching back and forth.

Going back is two words: set searchProvider/fetchProvider to deepseek-official and http. The bundle stays mounted and idle.

📖 Full configuration reference

Everything lives in one row, dsh-tinyfish. The row is validated, so an out-of-range value is rejected with a message rather than silently clamped.

keydefaultmeaning
channeldirectmonid or direct
apiKey(unset)literal credential for either channel; prefer a ref
apiKeyEnvTINYFISH_API_KEYcredential reference, or env var, for direct
monidKeyEnvMONID_API_KEYcredential reference, or env var, for monid
purpose(unset)goal statement; TinyFish ranks on it
attempts3retries for a transient failure or an empty search (1–5)
filters.domainType(unset)web | news | research_paper — patch file only
filters.language / .location(unset)geo targeting — patch file only
filters.includeDomains / .excludeDomains(unset)comma-separated — patch file only
monidBase / searchBase / fetchBaseupstreamendpoint override, for staging
search / fetchtrueoffer this kind at all; false declines without unregistering

Turning one off reports unavailable rather than missing — the harness tells those apart, and only the second means "the install is broken".

- id: dsh-tinyfish
  config:
    search: true
    fetch: false # keep TinyFish for search, let dsh-web use another fetch

Filters live in the patch file

filters is a nested object, and the settings form addresses one flat key per field — so search tuning stays operator-level:

- id: dsh-tinyfish
  config:
    channel: monid
    filters:
      domainType: research_paper
      language: zh
      includeDomains: arxiv.org,openreview.net

Where a credential comes from

Resolved per call — a rotated key takes effect on the next search, no restart. First match wins:

  1. the apiKey literal in the row (a secret in config; prefer 2–3)
  2. the credentials service — apiKeyEnv (direct) or monidKeyEnv (monid), saved from the settings UI
  3. the launch environment (exported before DSH started)
  4. the live environment (MONID_API_KEY / TINYFISH_API_KEY)
  5. the channel's CLI store (monid keys add / tinyfish auth login)

A failing service falls through to the next source rather than failing the search.

Where an endpoint comes from

Row, then environment, then built-in default — so staging can retarget without a patch:

settingenvironment variable
monidBaseTINYFISH_MONID_BASE_URL
searchBaseTINYFISH_SEARCH_BASE_URL
fetchBaseTINYFISH_FETCH_BASE_URL

🔍 Behaviour worth knowing

  • A 404 is a result, not an error. A per-URL fetch failure comes back carrying its status, because that is resource state the model needs.
  • publishedAt is honest. TinyFish reports human dates ("Apr 30, 2026", "1 year ago"). What parses becomes ISO-8601; what doesn't is dropped, never invented. Unzoned dates read as UTC, so the same page reports the same day everywhere.
  • Empty searches retry. The upstream answers a valid query with nothing about one run in three — a blank result is retried up to attempts before it is believed.
  • A blocked run is terminal. If a Monid workspace control stops a run, the error says why and links to top up. Never retried.

TinyFish's agent and browser surfaces are not exposed: metered, wallet-billed, and not a search or a fetch. Use the tinyfish CLI directly when a page genuinely needs a real browser.

🛠 Development

The toolchain is Vite+: vp pack builds with tsdown, vp test runs Vitest, vp lint / vp fmt are Oxlint and Oxfmt, type-aware. Lint and format live in vite.config.ts — Vite+ ignores standalone configs.

pnpm install
pnpm test               # 143 hermetic tests — no network, no credential
pnpm run check          # format + lint + types
pnpm run release:gate   # build, then the full gate incl. 11 package checks
pnpm run test:live      # the real APIs, still $0, needs credentials

Requires DSH 0.2.0+ and Node 24+. Full process and invariants: AGENTS.md. Contributing: CONTRIBUTING.md.

License

MIT