Models & Providers

dsh-smart-router

rouyiemei/dsh-smart-router · ★ 0

rouyiemei

Automatic model routing for DeepSeek Harness: three difficulty tiers (hard/normal/easy) plus vision routing, picking models you already configured under Settings ? Models. ???? + ?????????

License
MIT
Added
2026-08-16
Maintenance
active
Install kind
github
Manifest details
Manifest status
Declared
Manifest path
package.json#dsh
Manifest checked
2026-08-19
Lifecycle scripts
None found

Static manifest checks report declarations only; they are not compatibility or security review.

安装

dsh plugin --profile web add github:rouyiemei/dsh-smart-router

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. Why this exists
  2. What it solves
  3. Install
  4. How it works
  5. Settings (Settings → Smart Router)
  6. Coexistence with other vision plugins
  7. Development
  8. Acknowledgements (References)
  9. License

English · 简体中文

License: MIT DeepSeek Harness dsh-plugin

Why this exists

In August 2026, DeepSeek raised prices across the V4 family and introduced peak/off-peak pricing. Flash output tokens jumped from ¥2 to ¥4.5 (¥9 at peak); Pro went up 3–5×. My monthly bill went from ¥120 to ¥700+.

I tried everything. OpenCode Go's "affordable subscription" turned out to be the same official price with a monthly cap. MiMo-V2.5 was cheap but too weak for real coding. GLM-5.1 and Kimi K3 cost more than Flash. Subscription plans didn't help either — Xiaomi's Token Plan Pro covered my usage but couldn't match the quality; Zhipu's Coding Plan was too tight; Google AI Pro and ChatGPT subscriptions don't offer API access.

No single option could deliver both "no quality loss" and "affordable price."

887M tokens/month, 80% cached input — that was my usage profile with DS Flash. The price hike hit output tokens hardest, and most of my output was thinking tokens I couldn't just turn off.

Then it clicked: instead of finding one cheaper model to replace everything, let the same system call different models for different tasks. Simple file operations, formatting, and Q&A go to the cheap model; real reasoning and complex coding stay on Flash. Distribute on demand, not one-size-fits-all.

That's how dsh-smart-router was born. It's not an architectural breakthrough — just a practical tool born from sticker shock, routing each request to the best-fit model so you can find your own balance between capability and cost.

If AI API bills have ever stung you, hopefully this small tool saves you some money.

What it solves

  • Performance tiering: hard tasks (architecture, refactoring, tricky debugging) go to a strong model; easy tasks (small talk, wrap-ups, tiny edits) go to a cheap fast model; everything else hits the middle tier — like cc-switch's per-tier model slots for Claude Code, but for DSH.
  • Vision built in: many users add a separate vision plugin; this router integrates vision routing into itself. Requests with images → vision tier automatically; plain text → difficulty tiers. Out of the box it ships a free anonymous vision model (OVHcloud Qwen2.5-VL-72B-Instruct, no API key), replaceable with any vision-capable model you configured.
  • Cache friendly: pick all three tiers from the same vendor family (e.g. pro and flash editions of one series) for higher prefix-cache hit rates and lower cost (hint shown in the settings card).

Install

dsh plugin --profile web add dsh-smart-router

Restart dsh web, then:

  1. Open Settings → Smart Router: pick a model for each of the four rows (hard / normal / easy / vision). Dropdowns list the models you already configured; the vision row only lists models that declare image input.
  2. Back in chat, open the model picker and choose Smart Router (auto route).
  3. Chat normally — every request is classified and routed automatically.

Zero configuration also works: requests fall back to your default model (fail-open, never silently broken).

How it works

You pick the virtual model "smart" (declares text+image, passes DSH image admission)
        │
        ▼
SmartRouterAdapter.stream(request)
        │
        ├─ has image? ──────→ vision tier (free anonymous OVH by default) ──┐
        │                                                                │
        └─ else: classify ──→ hard → hard tier                             │
          (heuristic by    → normal → normal tier                          │
           default / LLM)  → easy → easy tier                              │
        │                                                                │
        ▼                                                                ▼
   ctx.llm.prepareCall({provider, model}).stream(request)  ← passthrough stream
        │
        └─ missing tier → hard→normal→easy→default ladder; error only when all fail
  • Routing happens at the LLM adapter layer (architecture from llm-adaptive / dsh-vision-mix): a virtual provider is registered; stream() decides per request and delegates via prepareCall().stream() — no host patches, no conflicts with other vision plugins.
  • Classifier modes: heuristic (default; zero cost — keywords + code volume + file references) or LLM (more accurate; one small call on the easy-tier model, 120s cache).
  • Image admission: the virtual model declares inputModalities: ['text', 'image'], so DSH's preflight (MODEL_DOES_NOT_SUPPORT_IMAGES) lets images through — no host patching (compare dsh-easyvision's patch approach).

Settings (Settings → Smart Router)

Setting Meaning
Enable routing Off = requests go to the session default model unchanged
Classifier heuristic (default) / llm
Hard / Normal / Easy { provider, model, effort } per tier; empty = unconfigured (ladder fallback)
Vision Default ovh-vision / Qwen2.5-VL-72B-Instruct (free, anonymous); replace with any configured vision model
Default fallback Empty = the session default model
LLM classifier Optional; defaults to the easy-tier model

Reasoning effort two-tier hierarchy: The reasoning effort in the chat input model selector (Off / High) is the master switch:

  • Off: reasoning disabled for all tiers (no extended thinking)
  • High: each tier uses the effort configured above (e.g. hardEffort=high, normalEffort=max, etc.)

A hint explaining this is shown in the tier models section of the settings page.

Manual config (~/.dsh/profiles/web/settings.yaml):

smart-router:
  enabled: true
  classifier: heuristic        # heuristic | llm
  hardProvider: deepseek-official
  hardModel: deepseek-v4-pro
  normalProvider: deepseek-official
  normalModel: deepseek-chat
  easyProvider: deepseek-official
  easyModel: deepseek-flash
  visionProvider: zhipu-vision # free quota; add GLM_API_KEY under Settings → Models
  visionModel: glm-4v-flash
  visionFallbacks: []
  fallbackProvider: ''
  fallbackModel: ''

On install the plugin idempotently seeds two free vision routes into llm-pi-ai (missing keys only, your config is never touched):

Route Model Cost
ovh-vision OVHcloud Qwen2.5-VL-72B-Instruct (anonymous endpoint) Free, no key (~2 req/min/IP)
zhipu-vision Zhipu GLM-4V-Flash Free quota; set GLM_API_KEY in Settings → Models

The vision default works out of the box; for more stable/stronger vision, point the vision row at any vision model you configured.

Coexistence with other vision plugins

The router only participates when the session model is smart; it never takes over existing provider routes and never touches the host, so modlens, dsh-vision-router and friends can stay installed side by side.

Development

npm test          # node --test tests/ (80 cases: classifier / chain / vision sidecar / config API / seed idempotency / schema)

Local install for debugging:

dsh plugin --profile web add C:\path\to\dsh-smart-router
dsh --profile web --dump-config | grep smart-router

Acknowledgements (References)

This plugin directly references the following open-source projects and DSH internals:

Project What was referenced
farion1231/cc-switch The per-tier model slot product shape (Claude Code's main/fast/thinking/vision tiers)
dylan121322/llm-adaptive Adapter-level routing: registerAdapter + prepareCall().stream() passthrough; LLM classifier rubric
BruceLanLan/dsh-tier-router Tier config schema shape and fallback/escalation trade-offs
haiziyao/dsh-vision-mix Declaring inputModalities: ['text','image'] at the adapter to pass DSH image admission (zero host patches)
liustack/modlens Structured vision evidence: summary/OCR/layout/semantics/visual/uncertainty template and the "vision parsing engine" prompt (source-level reference)
gloryxpnv/dsh-tool-vision Same structured JSON evidence template; the vision-bridge image→text replacement and fail-open pattern
ysr666/dsh-vision-router Free vision chain: anonymous OVHcloud endpoint (no key); image-admission analysis; per-image caching
s3yf1337/dsh-easyvision Reading model vision capability via resolveModelInfo().inputModalities
akqwpeter-prog/dsh-media-skills Idempotent free-vision route seeding into llm-pi-ai (zhipu-vision)
DeepSeek Harness internals dsh-llm (LlmAdapter / llm service / prepareCall contract), dsh-settings (installSettingsSection), dsh-agent-loop (agent/request waterfall), dsh-client-modules (client bundle contract)

License

MIT