Bundle
dsh-llm-auto-route
Provider discovery, matching, health checks, and pre-output failover for DeepSeek Harness.
- Source
- qinyu765
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 5 days ago
Readme
# dsh-llm-auto-route
`dsh-llm-auto-route` is a community Cordis plugin for DeepSeek Harness. It discovers which already-configured `dsh-llm-pi-ai` route should handle a request, explains the decision, and performs failover only before the first visible output.
It is deliberately a routing policy layer. It does not implement HTTP protocols, ship provider SDKs, or register `openai`, `anthropic`, `deepseek`, or other adapter routes. The official `@deepseek-ai/dsh-llm-pi-ai` plugin remains the owner of those routes.
> Community project: this package is not an official DeepSeek Harness package and does not imply DeepSeek endorsement.
## Requirements
- Node.js `>=22.19.0`
- DeepSeek Harness `0.1.0-rc.5` or a compatible `0.1.x` release
- `@deepseek-ai/dsh-llm-pi-ai` configured with the route names you want to select
The package is tested against the npm `0.1.0-rc.6` companion packages while keeping the peer range compatible with `rc.5`.
## Install
```bash
pnpm add dsh-llm-auto-route
```
The official base bundle already contains `@deepseek-ai/dsh-llm-pi-ai`. If you compose plugins manually, install and load that official adapter before this package. Load the shipped `cordis.patch.yml` with the normal DeepSeek Harness/Cordis composition command used by your deployment.
The patch adds one plugin named `llm-auto-route`; it does not add or replace any official adapter route.
## Configure the official adapter first
The route names in this plugin must already be registered by `dsh-llm-pi-ai`. The following is an abbreviated official-adapter configuration:
```yaml
- id: llm
name: '@deepseek-ai/dsh-llm-pi-ai'
config:
providers:
deepseek:
apiKeyEnv: DEEPSEEK_API_KEY
openai:
apiKeyEnv: OPENAI_API_KEY
anthropic:
apiKeyEnv: ANTHROPIC_API_KEY
ollama:
baseURL: http://127.0.0.1:11434/v1
api: openai-completions
models:
- id: llama3.1
contextWindow: 131072
maxTokens: 8192
vllm:
baseURL: http://127.0.0.1:8000/v1
api: openai-completions
models:
- id: local-model
contextWindow: 32768
maxTokens: 4096
openai-compatible:
apiKeyEnv: GATEWAY_API_KEY
baseURL: https://gateway.example.test/v1
api: openai-completions
models:
- id: gateway-model
contextWindow: 65536
maxTokens: 8192
```
`dsh-llm-pi-ai` owns credentials, model metadata, transport, and stream conversion. The auto-route plugin only sees the route directory and selects one of those route keys.
## Automatic selection
An automatic request uses `provider: auto`, or omits the provider when the plugin configuration's provider token is `auto`:
```ts
const options = {
provider: 'auto',
model: 'deepseek-chat',
messages,
}
```
The fixed default precedence is:
```text
explicit → provider_env → base_url → model_prefix
```
- A non-`auto` provider is always preserved. Explicit requests are never silently rerouted.
- `DEEPSEEK_API_KEY`, `OPENAI_API_KEY`, and `ANTHROPIC_API_KEY` are detection signals only; the key value is never written to a log.
- `LLM_BASE_URL` selects the generic `openai-compatible` rule. `11434` identifies Ollama and `8000` identifies a vLLM/OpenAI-compatible local endpoint.
- `deepseek-*`, `gpt-*`, `o1-*`, `o3-*`, and `claude-*` provide model-prefix hints.
- A candidate is usable only when the official adapter has registered the same route.
- Equal-priority candidates at the same stage return `AMBIGUOUS_ROUTE`; the plugin does not guess.
- A route's `defaultModel` is used only when a matching rule supplies one and the request omits its model.
Every selection can be explained without exposing credentials:
```text
已选择 deepseek/deepseek-chat;原因:发现 DEEPSEEK_API_KEY
```
Use an explicit provider or a route `priority` when an environment intentionally contains multiple credentials.
## Configuration
The shipped patch contains the default rules. An application can override them through its Cordis configuration:
```yaml
provider: auto
precedence:
- explicit
- provider_env
- base_url
- model_prefix
healthCheck:
mode: adaptive # off | adaptive | probe
timeoutMs: 3000
cacheTtlMs: 30000
failover:
enabled: true
maxAttempts: 3
diagnostics: info # silent | error | info
routes:
deepseek:
apiKeyEnv: DEEPSEEK_API_KEY
defaultModel: deepseek-chat
priority: 10
openai-compatible:
apiKeyEnv: GATEWAY_API_KEY
baseURLEnv: LLM_BASE_URL
modelPrefixes: [gateway-]
```
Route fields are hints, not adapter configuration:
| Field | Meaning |
| --- | --- |
| `provider` | Registered route id to return; defaults to the `routes` key. |
| `apiKeyEnv` | Non-empty environment variable used as a provider-env signal and for discovery. |
| `baseURL` / `baseURLEnv` | Exact or user-supplied endpoint hint. `baseURLEnv` also supports unknown OpenAI-compatible hosts. |
| `baseURLPatterns` | Additional normalized URL prefixes. |
| `ports` | Local ports that identify this route when a base URL is supplied. |
| `modelPrefixes` | Model id prefixes for automatic selection. |
| `defaultModel` | Model to use when the request does not name one. |
| `priority` | Tie breaker within one matching stage; higher wins. |
Do not put an API key directly in route configuration. Use the official adapter's credential reference, normally `apiKeyEnv`, and keep this plugin's `apiKeyEnv` aligned with it.
## Health checks and failover
`adaptive` health checks reuse the official `dsh-llm` model-discovery seam when it is available, with a bounded timeout and an in-memory cache. If a deployment cannot expose discovery, route/model resolution is used as the local fallback and the real stream remains the final availability check. `off` skips preflight checks. `probe` asks the discovery seam whenever the adapter exposes it.
Failover is intentionally conservative:
- it is allowed only before text, reasoning, tool-call, or block output has been emitted;
- buffered protocol metadata from a failed attempt is discarded before trying the next route;
- aborts, explicit providers, configuration errors, and requests that already emitted output are not retried;
- a later provider never receives a partial assistant response from an earlier provider.
The plugin observes `agent/request`, `agent/request-error`, and `llm/stream`. It returns a new immutable request configuration and never mutates a frozen request object.
## Public API
The package exports `AutoRouteConfig`, `RouteRule`, `RouteDecision`, `MatchStage`, and the pure helpers `normalizeConfig`, `normalizeBaseURL`, and `resolveRoute`:
```ts
import { normalizeConfig, resolveRoute } from 'dsh-llm-auto-route'
const decision = resolveRoute(normalizeConfig(), {
model: 'deepseek-chat',
env: { DEEPSEEK_API_KEY: 'present' },
registeredProviders: new Set(['deepseek']),
})
if (decision.kind === 'matched') {
console.log(decision.candidate.provider, decision.candidate.model, decision.stage)
}
```
`AutoRouteError.code` is stable for `AMBIGUOUS_ROUTE`, `MISSING_MODEL`, `NO_CANDIDATE`, and `NO_REGISTERED_ROUTE`.
## Troubleshooting
**`NO_REGISTERED_ROUTE`** — the route exists in this plugin's default hints but not in `ctx.llm.listProviders()`. Add the same key under the official adapter's `providers` configuration.
**`AMBIGUOUS_ROUTE`** — more than one candidate matched at the same stage and priority. Set `provider` explicitly, remove an unused environment variable, or give one route a higher `priority`.
**`MISSING_CREDENTIAL` / `INVALID_CREDENTIAL`** — detection and the official adapter must agree on the environment variable. Check the variable name, not its value in logs or issue reports.
**Local gateway is not selected** — set `LLM_BASE_URL`, or provide a URL containing port `11434` (Ollama) or `8000` (vLLM). The official adapter still needs a route with that key and a model catalog.
**A response was not retried** — this is expected after the first text, reasoning, tool-call, or block output, after cancellation, for an explicit provider, or for a configuration failure. Retrying then could duplicate or splice an assistant response.
## Compatibility and project status
This is an independent ecosystem plugin for the DeepSeek Harness developer preview. It follows the current upstream guidance for community plugins, `dsh-plugin` topics, Discussions announcements, and standalone repositories. It does not open a pull request against the official Harness repository.
Upstream references:
- [`dsh-llm-pi-ai` README](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/llm/llm-pi-ai)
- [LLM interface](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/llm/README.md)
- [Streaming and routing extension points](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/llm-streaming.md)
- [Contribution guide](https://github.com/deepseek-ai/deepseek-harness/blob/master/CONTRIBUTING.zh.md)
## License
MIT. See [LICENSE](LICENSE).
Install
dsh plugin --profile web add github:qinyu765/dsh-llm-auto-route
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-llm-auto-route from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.