Foreword

In agent development, you often encounter batches of heterogeneous tasks: one is mental arithmetic of 17×23, another requires writing code and verifying primes, and a third is long-form translation. Sending all of them to the same model results in simple tasks queuing up on flagship models, wasting time and tokens; handing difficult tasks to cheap models often leads to errors. Manually selecting models for each task is unmanageable as the number of tasks grows.

dsh-swarm-router solves this problem: it organizes a batch of heterogeneous tasks into a “sub-agent matrix swarm” — tasks are rows, candidate models are columns, the router selects a cell for each row, and then uses DSH’s ctx.subagents to turn each cell into an in-process sub-agent bound to the selected model for parallel distribution.

What is it

dsh-swarm-router is a DSH plugin maintained by GitHub user r600a-code, version 0.2.0, under the MIT license. A one-sentence positioning: route every task to the most suitable model (OpenRouter-like gateway + cfgpu.com/llm/square directory) and parallelly distribute them via in-process sub-agents (or direct ctx.llm calls) bound to the selected model.

Within DSH’s “everything is a plugin” system, it is packaged as a dsh.bundle manifest: dsh.bundle.patch in package.json points to ./cordis.patch.yml. The patch adds two independent LLM routes, cfgpu-swarm and openrouter, rather than modifying the original cfgpu configuration of the machine, so the swarm’s model directory does not interfere with the orchestrator’s own models.

How the Router Selects Models

The task structure is { id, kind, prompt, maxTokens? }, where kind ∈ {reasoning, coding, longcontext, fast, general}. The routing is a pure function, O(1) per task — it spends no model time to decide “which model to use,” and the saved overhead is fully invested in parallel distribution. Model selection consists of five steps:

  1. Infer kind: Explicitly provided kind takes priority; otherwise, take the first non-empty prompt in the order {reasoning, coding, longContext, fast}; if none exist, classify as general.

  2. Capability hard filtering (capability gate): Models lacking capability tags are directly marked as -∞ and eliminated. reasoning requires a reasoning tag, coding requires coding, longcontext requires longContext; fast and general have no thresholds.

  3. Weighted scoring by task type: For surviving models, calculate a linear score using the 1-10 rating (strength, speed, cost) and capacity (contextWindow, maxTokens) from the directory:

kind Scoring Formula
reasoning reasoning×3 + strength×2 + coding×0.3 + contextWindow×0.000004
coding coding×3 + strength×2.5 + longContext×0.3
longcontext contextWindow×0.00002 + strength×0.5 + coding×0.3
fast speed×3 + cost×1.5 + strength×0.3
general strength×2 + speed×0.6 + cost×0.3 + coding×0.3
  1. Asymmetric penalties: If kind is not fast but the model belongs to the fast tier, -2.0; if a general task hits a reasoning flagship, -2.0 (overkill, slower and more expensive); if a coding task hits a reasoning model, -0.5; models with unstable routing during directory collection (unstable), -4; unavailable models (e.g., OpenRouter without a configured key), -1000. When useRankings: true is enabled, rank feedback is added: success rate ≥ 0.9 and trial count ≥ 3 adds +1.5, success rate ≤ 0.4 subtracts -3.0.

  2. Select the best and explain: The highest scorer wins; if tied, compare strength first, then lexicographically by id. The tool returns the winner, as well as the scores of the top 5 candidates and readable reasons for the choice.

These numbers are asymmetric and intentional: rewarding cheap models on quality-oriented tasks is exactly the failure mode this design aims to avoid. The fast penalty and reasoning overkill penalty (each -2.0) are large enough to flip ties but small enough to allow truly strong cheap models to still win on general based on merit; the magnitude of rank bonuses (+1.5 / -3.0) is smaller than static penalties, meaning a model must first achieve real good performance before feedback becomes eligible to override directory ratings.

Core Capabilities

  1. Model aggregation registry + PR process: models/registry.json is the canonical directory; scripts/validate-registry.mjs validates the structure and can be directly integrated into CI; CONTRIBUTING.md records the PR process for adding new models.

  2. Plugin extension points: Plugins expose the API via ctx.provide('swarmRouter', api). Other plugins declare inject: ['swarmRouter'] to register runtime models, custom task types, subscribe to feedback events, and read rankings and usage.

  3. Real task feedback and ranking: swarm_feedback records {correct, quality 1-5} and persists to rankings.json; swarm_ranking shows success rates and quality scores by model and task type. Models with good empirical performance are weighted in routing, while those with poor performance are down-weighted — static directory ratings are just the author’s estimates; real task results will override them.

  4. Token consumption statistics: In direct mode, it precisely captures the prompt/completion/total of each call from the usage block of ctx.llm.stream (including reasoning_tokens from cfgpu if the adapter outputs it); in subagent mode, it captures via a global llm/stream listener and attributes the data to specific sub-agents based on sessionId == sub-run id. Data is persisted to usage.json, and swarm_stats displays summaries, details by provider, by model, and by task type, accompanied by cfgpuHighlight highlighting.

Tool Overview

Tool Mode Calls Model
swarm_route_preview No, pure routing preview
swarm_dispatch subagent (default) | direct Yes, parallel calls
swarm_models No, list registry
swarm_feedback No, record one result
swarm_ranking No, read cumulative feedback
swarm_stats No, read cumulative usage

“Decision” and “Execution” are separated: first use swarm_route_preview to see the complete routing plan without spending a token, then confirm and use swarm_dispatch for actual distribution. The subagent mode follows the full agent loop; the direct mode is a one-time ctx.llm.stream call, suitable for scenarios requiring precise token accounting.

Installation and Activation

By default, it installs to DSH_HOME (default ~/.dsh, which must already contain cfgpu credentials):

dsh plugin --profile headless add github:r600a-code/dsh-swarm-router

To verify installation, check if cfgpu-swarm and swarm-router appear in the configuration:

dsh --profile headless --dump-config | grep -E 'cfgpu-swarm|swarm-router'

If you want isolation from ~/.dsh, you can first prepare a workspace-level DSH_HOME, containing .credentials.yaml and settings.yaml with CFGPU_API_KEY, and install from the local path:

export DSH_HOME=/path/to/.dsh-home
dsh plugin --profile headless add /path/to/dsh-swarm-router

Credential requirements: The cfgpu route requires CFGPU_API_KEY in $DSH_HOME/.credentials.yaml (or environment variable); the OpenRouter route requires OPENROUTER_API_KEY. If missing, the router will report it as unavailable and will never distribute to it, though the profile can still start normally. Additionally, package.json’s peerDependencies declares five @deepseek-ai/* packages (cordis, dsh-tools, dsh-agent, dsh-llm, dsh-subagent), all of which are required.

Typical Usage: Running the Built-in Benchmark

benchmark/benchmark.json is the minimal benchmark set: 5 cheap, heterogeneous tasks covering fast/reasoning/coding/general. Success is determined by content (expected answer substring / CJK), not just completion.

subagent mode, 5 tasks:

dsh --profile headless "$(cat benchmark/benchmark_prompt.txt)"
node benchmark/verify_benchmark.mjs                                     # 27/27 green

direct mode, 3 tasks:

dsh --profile headless "$(cat benchmark/benchmark_direct_prompt.txt)"
node benchmark/verify_benchmark.mjs benchmark_direct_RESULT.json        # 31/31 green

Results recorded in the README: in subagent mode, 5 tasks are routed to 4 different real cfgpu models and all are correct (17×23=391, bat-ball=0.05, real is_prime, CJK translation, widgets=5); in direct mode, 3 tasks precisely capture token consumption per task. When a batch of tasks is spread across multiple models, distinctModels aggregation is the signal that “routing is working” rather than converging to a single model.

Applicable Scenarios and Notes

Suitable for three types of people: DSH users who frequently have batches of tasks with large difficulty differences and want to match models by difficulty; teams wanting to accumulate real task feedback and make the routing more accurate with use; and other plugin developers wanting to reuse the registry and rankings. For design details, there is a formal design document docs/PAPER.zh.md in the repository.

Notes before use:

  1. The plugin runs with the permissions of the current dsh process; please check the source code and license (MIT) yourself before installing.

  2. The cfgpu route cannot work without CFGPU_API_KEY; put credentials in $DSH_HOME before installing. The OpenRouter route missing a key will only make that route unavailable, not affecting startup.

  3. Benchmark numbers are based on the repository README: subagent validates 27/27, direct validates 31/31.

Conclusion

The philosophy of dsh-swarm-router can be summarized in three steps: make “selecting a model” a zero-cost pure function, hand “execution” to parallelly distributed sub-agents, and then use real task feedback to correct static directory ratings into your own rankings. For DSH users who frequently run heterogeneous task batches, this is a ready-to-use routing solution.

  • GitHub repository: https://github.com/r600a-code/dsh-swarm-router
  • Community directory page: https://www.skillhub.cn/plugins/r600a-code/dsh-swarm-router