dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
FreeLLMAPI (Auto) provider route for DeepSeek Harness: pick the auto model and a local FreeLLMAPI gateway chooses the best free model, fails over automatically, and streams back as native DSH chunks.
Free-tier multi-provider routing for DeepSeek Harness. Eighteen provider entries behind one DSH provider route — five of them enabled by default, and all five of those with a free tier — plus a per-request complexity classifier, capability/speed ranking, and automatic 429/5xx failover.
install the plugin → start DSH → pick provider "freellmapi" + model "auto" → it answers
No external process. No gateway to run. No API key required to get a first answer — the built-in pool contains keyless providers that the maintainer verified with real, credential-free requests.
Unofficial plugin — please read
This is a community project. It is not affiliated with, endorsed by, sponsored by or supported by any of the upstream providers it talks to, nor by DeepSeek. It is not an official DSH plugin. Provider names and "DeepSeek Harness" /
@deepseek-ai/*belong to their respective owners. Licensed under the MIT License. You are responsible for complying with each provider's terms of service, and for what you send to a free tier that may log and train on it.
autodirect and gatewayInstall — open the DSH web GUI, go to the Plugins manager in the sidebar, install the bundle and paste one of these specs:
github:lion231226/dsh-freellmapi # from GitHub (no npm publish needed)
github:lion231226/dsh-freellmapi#v0.7.18 # pinned to a tag
dsh-freellmapi # from npm, once published
CLI equivalent, and the manual path, are in Install details.
(Optional) paste a few keys — see Adding keys. Skipping this step is a supported configuration: the two keyless providers still answer.
Pick the model — in the DSH model picker choose provider FreeLLMAPI (Auto) and model auto.
Watch it work — with logRouting on (the default) every request logs one line:
dsh-freellmapi: tier=complex -> openrouter/nvidia/nemotron-3-ultra-550b-a55b:free (capability=5, speed=3, 2 candidates tried)
That is the whole setup. Everything below is detail.
| Method | How |
|---|---|
| Plugins manager (recommended) | Sidebar → Plugins → install → paste github:lion231226/dsh-freellmapi (or the npm name once published), confirm, restart if DSH asks. The manager accepts registry names, absolute paths, git addresses and tarball URLs, and refuses any spec whose manifest declares no dsh.bundle — this package declares one. |
dsh plugin CLI | dsh plugin --profile desktop add github:lion231226/dsh-freellmapi — the subcommands come from DSH's own runtime error text; ⚠️ not verified end-to-end here, so confirm against your DSH build. |
| Manual placement | Copy the package to $DSH_HOME/profiles/<profile>/node_modules/dsh-freellmapi/, add it to both dependencies and dsh.profile.bundles in the profile's package.json, then run dsh plugin --profile <profile> install and restart. Listing it in bundles is what makes DSH load it at all. |
The package ships its own cordis.patch.yml (- insert: [{ id: freellmapi, name: 'dsh-freellmapi' }]),
so a correctly installed bundle needs no hand-written patch row. Never add a second row with the same
id in the profile's own cordis.patch.yml: two entries with one id abort bundle composition with
duplicate loader entry id "freellmapi".
| Self-contained routing | The plugin owns the routing intelligence. direct mode (the default) needs no gateway, no daemon, no Docker — nothing but DSH itself. |
| A built-in pool of 17 providers / 46 models | Groq, Cerebras, OpenRouter, Mistral, Z.ai (Zhipu), Volcengine Ark, LongCat, LLM7, Kilo, NVIDIA NIM and OVH AI Endpoints, plus the six 0.7.0 additions — ModelScope (魔搭), iFlytek Spark (讯飞星火), SiliconFlow (硅基流动), SambaNova, HuggingFace Router and Routeway — with per-model capability, speed, context window, vision and tool-calling facts. Only five of the seventeen are enabled out of the box. |
| Per-request complexity routing | Every request is scored and classified simple / medium / complex; the tier decides whether capability or speed dominates the ranking. A one-line "list the files here" and a 12-tool refactoring task do not go to the same model. |
| Automatic failover | A rate-limited (429), broken (5xx), timed-out or model_unavailable candidate is parked and the next-ranked one is tried — only before the first chunk has been sent, so a single answer is never spliced from two models. |
| Health tracking and cooldowns | The first retryable failure already parks the candidate (2 minutes), and each further consecutive failure escalates one step: 2 m → 10 m → 1 h → 24 h. Retry-After from the provider always wins; a rejected credential (401/403) parks that provider for 24 h. The scoring penalty decays with a 60-second half-life, so a single 429 is never a life sentence. |
| Zero-config start | Kilo and LLM7 answer without any credential; a fresh install has a non-empty candidate pool before you configure anything. |
| Honest diagnostics | One log line per request names the tier, the winner and how many candidates were tried; every failure is an in-band finish chunk with a stable code, never an exception. |
| No silent substitutions | Picking a concrete model id is a strict pin: if it has no credential, does not exist, or is cooling down, you get an explicit error with instructions instead of somebody else's answer. The model list shows only what can actually serve, plus one setup:<provider> signpost per unkeyed provider. |
gateway mode kept intact | The v0.1.0 behaviour — forwarding to an external freellmapi gateway — is still there behind mode: gateway, unchanged, for people who want the gateway's own bandit scoring, caching and fusion. |
The pool marks three providers keyless (no Authorization header at all). The maintainer verified
them with real requests on 2026-10-13 (_lead/live-probe-2026-10-13.md), sending no credential:
| Provider | Model | Result |
|---|---|---|
kilo (https://api.kilo.ai/api/gateway/v1) | nvidia/nemotron-3-super-120b-a12b:free | HTTP 200, real completion |
kilo | nvidia/nemotron-3-ultra-550b-a55b:free | free route, 550B class |
ovh (https://oai.endpoints.kepler.ai.cloud.ovh.net/v1) | gpt-oss-120b | HTTP 200 |
llm7 (https://api.llm7.io/v1) | DeepSeek-V4-Flash-0731 | HTTP 200 (anonymous) |
llm7 | codestral-latest | HTTP 200 (anonymous) |
kilo and llm7 are enabled by default, so those two carry the "install and it works" promise.
ovh is keyless too but disabled by default (2 requests/minute — far too tight to be in the default
candidate set); enable it explicitly if you want it.
Three things you should know before you rely on a keyless pool:
Keyless is not unlimited. Kilo is documented at ~200 requests/hour per IP, LLM7 at ~100/hour, OVH at 2 RPM. Quota numbers throughout this document come from the upstream registry baseline (2026-04) and may be stale; the plugin reacts to them rather than trusting them — a 429 parks that candidate and moves on.
Free traffic may be recorded and used for training. Kilo states this in its own provider registry (free prompts and completions are logged for training). If that is not acceptable to you, disable it:
providers:
kilo:
enabled: false
With kilo off, zero-config still works through llm7 alone.
Free model catalogs drift. During the 2026-10-13 probe, llm7 answered 400 model_unavailable for
gpt-oss-20b and GLM-4.6V-Flash — the same kind of id that worked the day before. The router treats
model_unavailable as a per-model condition: it parks that (provider, model) pair and tries the next
candidate instead of failing your request. Seeing one of these is normal operation, not a bug.
Keys are the single biggest quality upgrade: the default candidate pool is groq, cerebras, openrouter,
kilo, llm7, and adding the first three gives you the strong-and-fast models.
Set a key by exporting the environment variable named in apiKeyEnv — or store it through DSH's
credentials service, which is the first thing resolution consults. Resolution order is:
credentials service → config.providers[id].apiKey → environment variable named by apiKeyEnv → the
convention <PROVIDER_ID>_API_KEY. Empty values count as "not configured".
Where to edit in the GUI. Settings → Models lists this plugin's provider route (FreeLLMAPI) as an ordinary card, and the key rows render inside that card — one per upstream that is enabled but has no usable credential, each with a link to its key page, the environment-variable name it will be stored under, a password field and Save. Saving writes through DSH's credentials service, which is read without caching, so the key takes effect on the next request with no restart.
Two notes on the host's own editor, so its behaviour is not mistaken for a bug:
- The 编辑 button next to that card opens DSH's provider editor, which can only render fields for its own two provider families (
llm-deepseek,llm-pi-ai); for any other namespace it shows "other fields live incordis.patch.yml" and disables Save. That is a current host limitation and the key rows above are the answer to it.- The card shows a missing-credential dot while the root
apiKeyEnv(FREELLMAPI_API_KEY) is unset. Direct mode needs no such key — the dot refers to the optional gateway credential and can be ignored.The full field set (including the per-upstream
providersmap and the routing knobs) is on the plugin's own settings page: Settings → Plugins → dsh-freellmapi, generated from the schema; it is also editable incordis.patch.yml.The card offers a key field for the pool's default-enabled providers (
groq,cerebras,openrouter,llm7,kilo). The browser table is generated at build time from those defaults, so a provider you enable yourself throughproviders.<id>.enabledwill not grow a key row — set itsapiKeyEnvand store the credential directly in that case. That applies to all six providers added in 0.7.0, which ship disabled on purpose: enabling one of them does not make a key row appear in the card (this is the known gap recorded in the 0.6.1 changelog, not a bug).
Free-tier access is network-sensitive, so this section tells you how to measure, not what to believe.
It previously carried a table claiming groq and cerebras were region-blocked "and a key changes
nothing". That table was wrong, and the reason is worth keeping: the probe sent no Authorization
header. Measured 2026-10-15:
| Provider | No credential | Syntactically valid but bogus key |
|---|---|---|
groq | HTTP 403 | HTTP 401 → reachable, it just wants a real key |
cerebras | HTTP 403 | HTTP 401 → reachable |
ovh (keyless) | HTTP 200 | HTTP 403 → sending a key breaks a keyless provider |
So a 403 is never self-explanatory. It means one of three different things depending on what you sent: anonymous request rejected, credential rejected, or region rejected. Reporting one without the other is how the wrong table got written.
Probe correctly, per provider:
llm7, kilo, ovh) — send no Authorization header; 200 is healthy.Authorization: Bearer … header;
401 is healthy (the endpoint exists and refused politely), 200 is fine too.403 as ambiguous: it needs a second probe with the other method before it means anything.404/400/422 usually mean the path differs, not that the host is down.The request body is part of the method too. Probing a chat endpoint with a model id that does not
exist yields the opposite conclusion: modelscope answers 400 Invalid model id and sambanova
answers 404 model_not_found, and neither can be told apart from "this provider's chat needs no
credential" — the request never reached the credential check. Replaying the same request with a real id
from the catalog returned 401 from both. Same URL, same headers, different body, opposite verdict.
The gate automates the header split: node tools/gate.mjs --online → G7 probes every pool provider with
the method that suits it and prints the method beside each result, so the verdict can be audited rather than
trusted. G7 asks GET {baseURL}/models only, so read its green as "the host answers", not as "this
provider will serve you a completion once you add a key".
G10 answers the question G7 cannot. A host that answers says nothing about whether the specific model
ids we ship are still served — and that gap let the same defect ship three times: four OpenRouter ids and
two Groq ids that the provider had retired, each found by a person rather than by the gate. G10 compares every
declared id against what the catalogue actually lists. For a default-enabled provider a dead id blocks;
for a default-disabled one it is reported as latent and blocks the moment that provider is enabled. Catalogues
that need a credential are recorded as not checked — a 401 is not evidence that an id is missing.
Measured this way on 2026-10-15:
modelscope, xfyun,
siliconflow, sambanova and huggingface are reachable. routeway's anonymous chat path is the one
open AMBIGUOUS: without a credential its POST /chat/completions gets a Cloudflare interstitial
(403, HTML, "Attention Required"), while the same request with a bogus Authorization header
reaches the origin and gets a plain-JSON 401 Invalid API key. A single response cannot separate
anonymous rejected from region rejected; a real key, or a second egress IP, would settle it. Nothing
in this README depends on that path being open.Which egress each probe used is part of the result. The probe host runs a VPN in split-tunnel mode: traffic to mainland-Chinese destinations goes out direct, everything else goes through the proxy, whose exit is US-Los Angeles. The LA exit is the overseas path's location — it is not the host's location, and this README does not claim otherwise. So the results above split by path, and the split is stated rather than left to inference:
modelscope, xfyun and siliconflow — the three mainland-Chinese
hosts in the 0.7.0 additions. Each answered its probe over the direct path (xfyun and siliconflow
returned 401 to the bogus-credential probe; modelscope was also reached, see the doc-site note below).routeway's Cloudflare behaviour is measured on this path, which is why its 403 still cannot be
separated from a region rejection — see the AMBIGUOUS note above.401, RFC 6750 credential challenges, origin error JSON) do not depend
on the egress at all; "reachable from your network" does, which is why the path is recorded per provider.A tool limit is not a property of the site. An earlier draft of this section reasoned from a failed
web_fetch of a Chinese vendor documentation site — "hostname resolves to a non-public IP address" — to
"Chinese vendor and documentation sites are unreachable from this machine." That inference was wrong.
The message is this project's own DNS guard: a split-tunnel VPN answers DNS with fake-IP addresses
from the reserved benchmarking range 198.18.0.0/15, and web_fetch refuses to fetch any hostname that
resolves there. It rejected www.xfyun.cn and github.com in the same session with the same sentence,
which is what exposes it as a guard rather than a measurement. Re-measured (2026-10-15) over the direct path
with an ordinary HTTP client:
| Host | Result over the direct path |
|---|---|
www.xfyun.cn (vendor doc page) | HTTP 200, 128 382 B, 618 ms, Server: Tengine |
modelscope.cn | HTTP 200, 4 639 B, 290 ms |
spark-api-open.xf-yun.com (POST /v1/chat/completions) | HTTP 401, {"message":"HMAC signature cannot be verified: apikey not found"} |
siliconflow's api.siliconflow.com (GET /v1/models) | HTTP 401, {"code":30014,…"message":"Token is invalid."} |
So the Chinese documentation sites were always reachable from this machine; only web_fetch could not
read them. Any verdict about "sites in country X cannot be reached" needs a reachability measurement
(an HTTP client speaking to the host), never a fetch-tool error, because the latter reports the tool's
policy and the former reports the network.
And when a provider genuinely is unreachable from your network, turning it off is the whole change, in
$DSH_HOME/profiles/<profile>/cordis.patch.yml (or the plugin's own providers field):
- id: freellmapi
config:
providers:
someprovider: { enabled: false }
Key request pages (the first seven were verified reachable on 2026-10-14):
groq https://console.groq.com/keys, cerebras https://cloud.cerebras.ai/,
openrouter https://openrouter.ai/keys, mistral https://console.mistral.ai/api-keys,
zhipu https://open.bigmodel.cn/usercenter/apikeys, volcengine https://console.volcengine.com/ark,
longcat https://longcat.chat/platform/api_keys.
The six 0.7.0 additions' key pages below are the pool's own keyURL values and were not independently
verified — only modelscope's carries an upstream citation. (An earlier draft justified that gap with the
claim that Chinese vendor/documentation sites "resolve to non-public addresses" from this machine. That
claim is withdrawn: it was a web_fetch DNS-guard artefact, and the vendor doc page was in fact fetched
over the direct path — see the reachability table above. The key pages themselves remain unverified; only
the reason previously given for that was wrong.)
| Provider | apiKeyEnv | Key page | Free tier (upstream baseline) | Default | Notes |
|---|---|---|---|---|---|
groq | GROQ_API_KEY | https://console.groq.com/keys | 30 RPM / 1000 RPD / ~8K TPM / 200K TPD | ✅ on | Fast; openai/gpt-oss-120b, qwen/qwen3.8-27b, openai/gpt-oss-20b (ids re-measured 2026-10-15: two older ids had been retired upstream) |
cerebras | CEREBRAS_API_KEY | https://cloud.cerebras.ai/ | 30 RPM / no RPD / 60K TPM / 1M TPD | ✅ on | Two models rated capability 5 and speed 5; upstream notes a second, tighter quota revision (5 RPM / 30K TPM) |
openrouter | OPENROUTER_API_KEY | https://openrouter.ai/keys | 20 RPM / 200 RPD | ✅ on | The complex tier's main supplier (nvidia/nemotron-3-ultra-550b-a55b:free, nemotron-3-super-120b-a12b:free, cohere/north-mini-code:free) |
llm7 | LLM7_API_KEY | https://token.llm7.io/ | ~100 req/hour | ✅ on | Keyless works; a key raises the ceiling. Key page is reported, not independently verified |
kilo | KILO_API_KEY | — | ~200 req/hour per IP | ✅ on | Keyless works. Free traffic is logged for training |
mistral | MISTRAL_API_KEY | https://console.mistral.ai/api-keys | 500K TPM | ⬜ off | mistral-large-latest, magistral-medium-latest, codestral-latest |
zhipu | ZHIPU_API_KEY | — | ~1M TPD | ⬜ off · ⚠️ speculative | glm-4.7-flash, glm-4.6v-flash. baseURL is the single riskiest row in the pool: the mainland and overseas sites do not share keys, and picking the wrong hostname gives a guaranteed 401. Enable it only if you know which site your key belongs to. |
volcengine | ARK_API_KEY | — | ~2M TPD | ⬜ off · ⚠️ speculative | Chinese provider, real-name registration required; the model id is inferred, not verified |
longcat | LONGCAT_API_KEY | — | — | ⬜ off · ⚠️ speculative | No real-name requirement; model id inferred, not verified |
nvidia | NVIDIA_API_KEY | — | 40 RPM | ⬜ off | High capability ceiling (qwen/qwen3-coder-480b-a35b-instruct), but "evaluation only" trial ToS, first token can take minutes, and see the known gap in Limitations |
ovh | OVH_AI_ENDPOINTS_KEY | — | 2 RPM | ⬜ off | Keyless works, but 2 RPM only |
modelscope | MODELSCOPE_API_KEY | https://modelscope.cn/my/myaccesstoken | Upstream wrote 2 000 req/day, then marked that figure historical (billing moved to magic grains 魔粒) | ⬜ off | Alibaba's ModelScope (魔搭). A token only serves traffic once the account is bound to an Alibaba Cloud China-site account with Chinese real-name verification — unbound tokens answer 401 please bind your alibaba cloud account before use on every call. Its GET /models answers 200 for any credential, so it cannot validate a key; use a 1-token chat instead |
xfyun | XFYUN_API_KEY | https://console.xfyun.cn/ | No published token/QPS ceiling — upstream sets null rather than guessing | ⬜ off · ⚠️ speculative | iFlytek Spark (讯飞星火). Chinese real-name verification required. Auth is the console APIPassword as a bearer token. Its model id lite is now vendor-documented, not a placeholder: the official HTTP API page (spark-api-open.xf-yun.com/v1, fetched 2026-10-15 over the direct path) lists 4.0Ultra / generalv3.5 / max-32k / generalv3 / pro-128k / lite as the accepted model values, and its version table describes Lite as 轻量级 and 支持免费使用 (supports free use). Still not exercised with a valid credential here; confidence stays speculative |
siliconflow | SILICONFLOW_API_KEY | https://cloud.siliconflow.com/account/ak | No recurring free chat tier — the .com endpoint is a one-time $1 trial credit | ⬜ off · ⚠️ speculative | SiliconFlow (硅基流动). Chinese real-name verification required. Upstream keeps the platform for its free generative-media models (image/TTS), which this plugin's LLM seam cannot consume; the chat model it once listed is paid ($0.06/M) and upstream deleted that row |
sambanova | SAMBANOVA_API_KEY | https://cloud.sambanova.ai/apis | None — the free tier was permanently retired. With a vali |