# dsh-model-tier

> 为 DSH 提供模型分档路由：按会话把辅助请求与子任务分流到轻量模型，主对话与复杂任务走强档，跨 provider 生效。

## Metadata

- Author: [@biociao](https://github.com/biociao)
- Repo: <https://github.com/biociao/dsh-science.git>
- GitHub: [biociao/dsh-science](https://github.com/biociao/dsh-science)
- Stars: 23
- Language: JavaScript
- License: [MIT](https://spdx.org/licenses/MIT.html)
- Topics: `dsh-plugin`, `dsh-plugins`
- Forks: 3
- Open Issues: 1
- Last push: 2026-08-18T09:50:28.000Z
- Added: 2026-08-20T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add dsh-model-tier
```

## Wiki

## One-Sentence Description
A session-level model tier routing plugin for DeepSeek Harness: automatically routes auxiliary requests (title/compaction) and sub-tasks in a session to lightweight models, escalates complex tasks to strong-tier models, main conversation follows the tier scheme, and each tier can point to different providers.

## Core Features
- Register a virtual provider "Smart Tiering" in the session model selector, converting multiple tiering schemes into selectable "models", enabling routing per-session via opt-in; unaffected sessions remain completely untouched
- Auto-decide tiers by request type: auxiliary requests (session title, compaction) go to light tier, sub-tasks go to light tier, main conversation goes to default tier
- Escalate to strong tier by rules: optional "recent user message exceeds N characters" / "sub-agent chain depth ≥ N" triggers strong tier, automatically routing long inputs and deep-chain reasoning to stronger models
- Optional LLM pre-classifier: uses a small model to classify tasks as light/default/strong on top of structural rules, cached by (sessionId, message hash), classifies only once per round, falls back to structural tier on failure/timeout
- Multi-scheme presets + hot reload: settings page can save multiple tiering schemes, config file hot-reloads by mtime, no profile restart needed
- Cross-provider routing: three tiers can point to different providers/models respectively; when a tier is unconfigured, falls back in order default → light → strong, then passes through global default model

## Technical Implementation
- **Language**: JavaScript (ESM, Node built-in modules)
- **Key Dependencies**: Zero third-party dependencies; only uses `node:fs`, `node:path`, `node:os`, `node:url`
- **Architecture Pattern**: Registers process-level virtual LLM adapter via `ctx.llm.registerAdapter(["model-tier"], ...)`; subscribes to `agent/request` event for global default model fallback guard; client injects "settings page section" and "chat page bottom dock" via `slots.inject`
- **Entry Files**: `engines/model-tier.mjs` (routing engine, exports `name = "dsh-model-tier"`, `inject = ["llm"]`) + `engines/model-tier-ui.mjs` (settings page HTTP routes) + `client/model-tier-ui/src/index.js` (settings page + routing metrics UI)

## Use Cases
Users who want to simultaneously use strong models from different providers (e.g., DeepSeek, Zhipu) and cheap/local lightweight models, wanting to automatically route models by request type within the same session to save token costs and latency. Suitable for multi-model collaboration (flagship for default tier, local small models for light tier, reasoning-strong models for strong tier) in development, research, and automation workflow scenarios. Claude Code users migrating to DSH can seamlessly reuse the "small model handles auxiliary requests" tiering approach.

## Prerequisites & Compatibility
| Dependency | Min Version | Description |
|---|---|---|
| Node | >= 18 | Declared in `package.json` `engines.node` |
| DSH | Not declared | No `dsh` version field in `package.json`, runs on currently released DSH host |
| Platform | Cross-platform | No platform-specific native modules on server; client declares `dsh.client.platform: "web"` |
| Native Modules | None | Only depends on Node built-in modules (fs/path/os/url) |

## Installation
```bash
dsh plugin --profile web add dsh-model-tier
```

## Configuration Options
| Config | Type | Description | Default |
|---|---|---|---|
| `tiers.strong` | Object | Strong tier `{provider, model, reasoningEffort?}`, for complex tasks (deep-chain sub-tasks / super long inputs) | Unconfigured → falls back to default tier |
| `tiers.default` | Object | Default tier, main conversation in selected sessions goes through this tier | Unconfigured → falls back to light/strong tier |
| `tiers.light` | Object | Light tier, for auxiliary requests (title/compaction) + sub-tasks | Unconfigured → falls back to default tier |
| `routing.auxiliary` | String Array | `purpose` list treated as auxiliary requests, auto go to light tier | `["session-title", "compaction"]` |
| `routing.subagents` | String | `"light"` means sub-tasks route to light tier; other values don't route | `"light"` |
| `routing.subagentDepthStrong` | Number/null | Escalate to strong tier when sub-agent `delegationDepth ≥ N` | `null` (off) |
| `routing.escalateOnChars` | Number/null | Escalate to strong tier when latest user message text length ≥ N (after stripping harness-injected `<system-reminder>` segments) | `null` (off) |
| `routing.classify` | Object/null | LLM pre-classifier: `true`/`{}` enables (defaults to light tier model for classification), or explicitly specify `{provider, model, timeoutMs?, maxChars?, maxTokens?}`; non-thinking model recommended | `null` (off) |
| `enabled` | Boolean | Master switch: when off, "Smart Tiering" no longer appears in model selector | `true` |

> When all three tiers are unconfigured, no tiering scheme appears in the model selector, so sample config can be safely shipped with the package without polluting environments that don't expect the provider.

## FAQ

**Q: What's the relationship between this plugin and Claude Code's Opus/Sonnet/Haiku strategy?**

A: It's the DSH implementation of the same idea: within the same session, automatically route auxiliary requests (title/compaction) and sub-tasks to light tier, main conversation goes to default tier, complex tasks escalate to strong tier by rules, corresponding to Claude Code's smallModel/--model-small and task complexity judgment.

**Q: Will all sessions be automatically tiered after installation?**

A: No. The plugin only registers a virtual provider "Smart Tiering" in the session model selector. You need to manually select "Smart Tiering / some scheme" in each session to enable routing. Unselected sessions remain completely unaffected (opt-in per session, no global routing).

**Q: Where is the config file saved? Do I need to restart after changes?**

A: Saved to `$DSH_HOME/model-tier.json` (default `~/.dsh/model-tier.json`). Routing engine caches by file mtime, changes take effect hot, no need to restart profile or reopen session.

**Q: Is LLM pre-classifier (routing.classify) required?**

A: No. It's an optional enhancement: when enabled, every user question or sub-task dispatch will use a small model to classify the task as light/default/strong, overriding the structural tier. Defaults to light tier model for classification; failure/timeout/garbage response automatically falls back to structural tier (won't block main request).

**Q: Can I use a thinking model for the classifier target?**

A: Not recommended. Reasoning content from thinking models also consumes maxTokens quota (default 512, adjustable via maxTokens). In testing, thinking has filled the quota and produced empty strings where classification words couldn't be obtained. README explicitly recommends non-thinking models.

**Q: What's the relationship with dsh-science?**

A: dsh-model-tier is a companion package to dsh-science. Installing dsh-science automatically brings dsh-model-tier as a dependency; but it's completely independent and can be used in any profile alone via `dsh plugin add dsh-model-tier`.

## Difficulty Level
Beginner — configuration only involves three-tier provider/model YAML, after writing yaml you can see "Smart Tiering" group in model selector and enable it in sessions; advanced features (classifier, deep-chain escalation) have clear switches and defaults.

## Known Issues & Limitations
- **Selection window race condition (known limitation)**: Since platform persists "session model selection" as global default model, engine uses `agent/request` listener for best-effort fallback; however, sessions created in the extremely short window between "selecting scheme" and "next request" will still inherit the tiering scheme (source: `README.zh.md:48-49`, `engines/model-tier.mjs:651-681`)
- **Cross-tier thinking compatibility**: When history mixes assistant messages from other tiers (non-thinking / no reasoning capture) producing tool calls, and target tier is a thinking model like DeepSeek that requires `reasoning_content` return, it triggers 400 INVALID_REQUEST. Engine automatically adds placeholder reasoning content to messages missing reasoning blocks and retries transparently once (generates warn log, but only retries once, doesn't replay already produced content; source: `engines/model-tier.mjs:344-369`)
- **Classifier cache limit 200 items**: Classification results cached by (sessionId, message hash), items evicted by insertion order when limit exceeded; occasional duplicate classification in long-session dense scenarios is normal (source: `engines/model-tier.mjs:318-323`)
- **Light tier model reasoning effort**: Explicit `reasoningEffort` in tier is forwarded as-is; model's reasoning effort in selector is only forwarded when target model declares support, otherwise host hard-fails with `UNSUPPORTED_REASONING_EFFORT`; light tier models typically don't support reasoning, auxiliary requests like title/compaction will silently fall back (source: `engines/model-tier.mjs:622-639`)
- **Unconfigured tier schemes don't go live**: If a scheme saved in settings page has all three tiers incompletely configured with provider/model, corresponding tiers fall back in TIER_FALLBACK order, and when still no target available, throws error "No available model" (source: `engines/model-tier.mjs:294-303`, `engines/model-tier.mjs:597-606`)

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-model-tier](https://deepseek-plugin.org/plugins/biociao/dsh-science/packages/dsh-model-tier)
Wiki generated by AI (model: `MiniMax-M2.5`)
