router-brain 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. router_brain-1.1.0/LICENSE +21 -0
  2. router_brain-1.1.0/PKG-INFO +229 -0
  3. router_brain-1.1.0/README.md +211 -0
  4. router_brain-1.1.0/pyproject.toml +35 -0
  5. router_brain-1.1.0/setup.cfg +4 -0
  6. router_brain-1.1.0/src/router_brain/__init__.py +15 -0
  7. router_brain-1.1.0/src/router_brain/__main__.py +3 -0
  8. router_brain-1.1.0/src/router_brain/classifier.py +33 -0
  9. router_brain-1.1.0/src/router_brain/cli.py +272 -0
  10. router_brain-1.1.0/src/router_brain/config.py +198 -0
  11. router_brain-1.1.0/src/router_brain/credentials.py +53 -0
  12. router_brain-1.1.0/src/router_brain/dashboard.py +150 -0
  13. router_brain-1.1.0/src/router_brain/degrade.py +278 -0
  14. router_brain-1.1.0/src/router_brain/executor.py +413 -0
  15. router_brain-1.1.0/src/router_brain/live.py +56 -0
  16. router_brain-1.1.0/src/router_brain/llm_api.py +250 -0
  17. router_brain-1.1.0/src/router_brain/logger.py +45 -0
  18. router_brain-1.1.0/src/router_brain/models.py +105 -0
  19. router_brain-1.1.0/src/router_brain/openrouter_sync.py +99 -0
  20. router_brain-1.1.0/src/router_brain/provider_catalog.py +103 -0
  21. router_brain-1.1.0/src/router_brain/router.py +48 -0
  22. router_brain-1.1.0/src/router_brain.egg-info/PKG-INFO +229 -0
  23. router_brain-1.1.0/src/router_brain.egg-info/SOURCES.txt +30 -0
  24. router_brain-1.1.0/src/router_brain.egg-info/dependency_links.txt +1 -0
  25. router_brain-1.1.0/src/router_brain.egg-info/entry_points.txt +2 -0
  26. router_brain-1.1.0/src/router_brain.egg-info/requires.txt +4 -0
  27. router_brain-1.1.0/src/router_brain.egg-info/top_level.txt +1 -0
  28. router_brain-1.1.0/tests/test_classifier.py +61 -0
  29. router_brain-1.1.0/tests/test_credentials.py +43 -0
  30. router_brain-1.1.0/tests/test_degrade.py +56 -0
  31. router_brain-1.1.0/tests/test_executor_plan.py +188 -0
  32. router_brain-1.1.0/tests/test_router.py +97 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 router-brain contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,229 @@
1
+ Metadata-Version: 2.4
2
+ Name: router-brain
3
+ Version: 1.1.0
4
+ Summary: 模型路由大脑:分析任务 → 从模型池选模型 → 派给 DeepSeek Harness headless agent 执行 → 失败降级重试 → 汇总结果
5
+ Author: router-brain contributors
6
+ License: MIT
7
+ Keywords: llm,routing,agent,deepseek-harness,model-router,multi-model
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: PyYAML>=6.0
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=7.0; extra == "dev"
17
+ Dynamic: license-file
18
+
19
+ # router-brain · LLM Routing Brain
20
+
21
+ > **English**: this file · **中文**: [README_CN.md](README_CN.md)
22
+
23
+ > **Separate decision from execution**: a small "brain" model makes decisions (decompose → pick model → dispatch → read feedback); focused workers do one short-context subtask each. Use the right model for the right job, verify across models, fight hallucinations, and save money.
24
+
25
+ > **AI orchestration framework · multi-model router · prompt automation · DeepSeek Harness** — You don't need to know how to write prompts: tell it *what* you want, and the brain decomposes the task, writes the subtask prompts, picks the model, sets the reasoning effort, dispatches workers, reads feedback, and iterates until done.
26
+
27
+ <p align="center">
28
+ <a href="https://github.com/ZzkAItech/router-brain"><img alt="GitHub stars" src="https://img.shields.io/github/stars/ZzkAItech/router-brain?style=flat-square&label=Stars"></a>
29
+ <a href="https://github.com/ZzkAItech/router-brain"><img alt="GitHub forks" src="https://img.shields.io/github/forks/ZzkAItech/router-brain?style=flat-square&label=Forks"></a>
30
+ <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-brightgreen?style=flat-square"></a>
31
+ <a href="https://www.python.org/"><img alt="Python" src="https://img.shields.io/badge/python-3.10+-blue?style=flat-square"></a>
32
+ <a href="https://github.com/ZzkAItech/router-brain/actions"><img alt="tests" src="https://github.com/ZzkAItech/router-brain/actions/workflows/test.yml/badge.svg"></a>
33
+ </p>
34
+
35
+ ---
36
+
37
+ ## Problems it solves
38
+
39
+ ### 🎯 Problem 1: LLMs lose focus in long contexts
40
+
41
+ **Problem**: Shove a whole long task into one model and it must hold the goal, background, progress, and current step all at once. The longer the context, the more it drifts ("lost in the middle").
42
+
43
+ **router-brain's approach**: **Separate decision from execution.**
44
+ - The **brain model only decides** — it sees "goal + current state + who to dispatch". It never touches execution details, so its attention stays on judgment.
45
+ - Each **worker handles one short-context subtask** — it only focuses on the one thing in front of it.
46
+
47
+ > The brain doesn't do the work, so the brain doesn't tire; the worker does one thing, so it doesn't get lost.
48
+
49
+ ### 🌀 Problem 2: Hallucination
50
+
51
+ **Problem**: A single model generates once, with no one checking. In multi-step tasks one hallucinated step corrupts everything downstream.
52
+
53
+ **router-brain's approach**: **Dispatch → feedback → re-dispatch loop.**
54
+ - Brain dispatches → worker finishes → **result returns to the brain**;
55
+ - Brain checks whether it meets the bar; if not, **re-dispatch / switch model** until done or truly unsolvable;
56
+ - Key conclusions are **cross-validated by different models** — one model may fool you, several rarely fool you together.
57
+
58
+ ### 💰 Problem 3: Uncontrollable cost
59
+
60
+ **Problem**: Using an expensive model for everything burns money; using cheap ones for everything can't handle hard tasks.
61
+
62
+ **router-brain's approach**: **Right-size the spend, cheap-first.**
63
+ - The **brain uses a cheap/free model** (it only judges, doesn't need the strongest);
64
+ - **Simple tasks (QA/classify/extract) go direct** — instant reply, no agent boot;
65
+ - **Complex tasks dispatch a worker**, trying cheap → expensive in order;
66
+ - Hooks into **free quotas** automatically.
67
+
68
+ ### 🔗 And deeper problems it solves
69
+
70
+ - **No vendor lock-in**: models are a pluggable pool — switch providers by editing config, not code.
71
+ - **One API down doesn't stop the task**: multi-channel failover + circuit breaker + retry.
72
+ - **Long tasks survive mid-way failures**: subtasks are independent; retry only the failed step.
73
+ - **Quotas stay managed**: cheap-first + healthcheck + auto-degrade low-quota channels.
74
+ - **Context stays small**: decision/execution separation keeps each worker's context short.
75
+ - **Model lifecycle handled**: deprecated models auto-fuse; `sync-free-models` pulls the latest.
76
+ - **Multi-model as a team**: pick the best for each job, cross-validate key results.
77
+
78
+ ### ✍️ Can't write prompts? The brain writes them
79
+
80
+ You only state the **goal** ("refactor this project", "turn this data into a report"). The brain:
81
+ - decomposes into subtasks and **writes each subtask's prompt** (with guardrails, output path, format);
82
+ - **picks the model** — you don't need to know which model is good at what;
83
+ - **sets reasoning effort** — light for simple steps, heavy for deep reasoning.
84
+
85
+ ---
86
+
87
+ ## Architecture in one line
88
+
89
+ ```
90
+ You (goal)
91
+ └─> 🧠 Brain (cheap model, decides only) ──decompose──> 👷 Worker 1 (model A, one task)
92
+ ├──> 👷 Worker 2 (model B, another task)
93
+ └──> 🔁 feedback back; re-dispatch / switch if not OK
94
+ ```
95
+
96
+ - **Decision plane** (this process): classify → pick model → dispatch → read feedback → decide next.
97
+ - **Execution plane** (DeepSeek Harness headless agent): a real agent with tools (bash/files/workspace) actually does the work.
98
+
99
+ > Every worker is a **real agent** — not "ask a question, get text back", but "write files, run scripts, read results".
100
+
101
+ ---
102
+
103
+ ## Quick start
104
+
105
+ ### 1. Install
106
+
107
+ ```bash
108
+ cd router-brain
109
+ python3 -m venv .venv && . .venv/bin/activate
110
+ pip install -e .
111
+ ```
112
+
113
+ Only dependency is PyYAML. Requires **DeepSeek Harness** installed (`dsh` on PATH).
114
+
115
+ ### 2. Configure your model pool
116
+
117
+ router-brain ships **no models/channels** — it's a scheduling framework; you add yours.
118
+
119
+ `config/pool.yaml` is a template. Fill in:
120
+ - **providers**: API channels (base_url + credential key name)
121
+ - **models**: the models you can use (id + channel + cost + kind)
122
+
123
+ Credentials go in `~/.dsh/.credentials.yaml` or same-named env vars; the framework reads them and **never prints keys**. Changes take effect immediately — no restart.
124
+
125
+ ### 3. Run
126
+
127
+ ```bash
128
+ router-brain list-models # see your pool
129
+ router-brain route "write a python script" # routing decision only (no execution)
130
+ router-brain run "turn /tmp data into a report" # route → dispatch → fallback → summary
131
+ ```
132
+
133
+ ### 4. (Optional) Enable the "Router Brain" commander in DeepSeek Harness
134
+
135
+ The repo ships `agent-presets/router-brain/` (commander persona + dispatch skill). Enable it and a new **「路由大脑 / Router Brain」** preset appears in the DSH session picker — it becomes a persistent commander: give it a goal, it decomposes, dispatches, reads feedback, iterates to completion, and gives a final summary.
136
+
137
+ ```bash
138
+ mkdir -p ~/.dsh/.agent-presets
139
+ cp -r agent-presets/router-brain ~/.dsh/.agent-presets/
140
+ # restart dsh web, pick 「路由大脑」 in the new-session picker
141
+ ```
142
+
143
+ > The preset ships only the commander tools (bash/fs/jobs/goal/todo/skill) and no models — brain and workers both use models from *your* `config/pool.yaml`.
144
+
145
+ ---
146
+
147
+ ## Highlights
148
+
149
+ | Capability | Description |
150
+ |---|---|
151
+ | Decision/execution separation | Brain judges, worker executes → fights attention drift |
152
+ | Dispatch-feedback-re-dispatch | Results return; re-dispatch/switch on failure → fights hallucination |
153
+ | Cross-model validation | Key results validated by different models, never self-proven |
154
+ | No hardcoded division | Brain decides allocation at runtime |
155
+ | Multi-channel failover | One model on many channels; auto-switch on limit/shutdown |
156
+ | Retry + degrade + fuse | 429/timeout/5xx retry; fallback chain; circuit breaker |
157
+ | Permanent-error fuse | Deprecated/not-found models fuse instantly |
158
+ | Cheap-first | Defaults to free/low-cost available models |
159
+ | Direct fast-answer | QA/classify/extract reply instantly, no agent boot |
160
+ | Worker channel switch | `worker:false` marks brain-only channels |
161
+ | Millisecond classifier | Deterministic rules, zero cost, zero latency |
162
+ | Program-readable decision | `route` emits JSON for the brain or other programs |
163
+ | Full-task trace | `task_id` through everything; JSON logs, no secrets |
164
+ | healthcheck | Probe the whole pool to see what actually works |
165
+
166
+ ---
167
+
168
+ ## Configuration
169
+
170
+ ### config/routing.yaml
171
+
172
+ ```yaml
173
+ execution:
174
+ max_retries: 2 # transient-failure retries
175
+ max_fallbacks: 4 # model-fallback cap
176
+ timeout_seconds: 600 # per-task timeout
177
+ auto_failover: false # false = stop and let the brain choose
178
+ force_channel: "" # "" = all channels; a name = only that channel
179
+ direct_max_tokens: 2048 # direct-mode token budget
180
+ ```
181
+
182
+ ### config/pool.yaml template
183
+
184
+ ```yaml
185
+ providers:
186
+ my_channel:
187
+ base_url: https://api.example.com/v1
188
+ credential_key: MY_API_KEY # put the key in ~/.dsh/.credentials.yaml
189
+
190
+ models:
191
+ my-model:
192
+ kind: general
193
+ cost: low
194
+ context: 131072
195
+ providers:
196
+ - {channel: my_channel, dsh_provider: my_channel}
197
+ ```
198
+
199
+ ---
200
+
201
+ ## Directory
202
+
203
+ ```
204
+ router-brain/
205
+ ├── config/
206
+ │ ├── pool.yaml your model pool (template)
207
+ │ └── routing.yaml routing rules + execution params
208
+ ├── agent-presets/
209
+ │ └── router-brain/ DSH preset (copy to ~/.dsh/.agent-presets/ to use)
210
+ ├── src/router_brain/
211
+ │ ├── config.py config + pool/channel/degrade management
212
+ │ ├── router.py model selection
213
+ │ ├── degrade.py retry + degrade + circuit breaker
214
+ │ ├── executor.py agent/direct execution
215
+ │ ├── llm_api.py direct-mode client (error classification)
216
+ │ └── cli.py CLI entry
217
+ ├── tests/ unit tests (fully offline)
218
+ ├── CONTRIBUTING.md contribution guide
219
+ ├── CHANGELOG.md changelog
220
+ ├── LICENSE MIT
221
+ └── README.md this file
222
+ ```
223
+
224
+ ## Security
225
+
226
+ - Never reads-and-prints any key; direct mode resolves once, agent mode never touches keys.
227
+ - Worker subprocess cwd = `--cwd`; file permissions follow DSH sandbox policy.
228
+ - healthcheck consumes real API quota (~a dozen tiny calls per full run).
229
+ - Keys never appear in logs or output.
@@ -0,0 +1,211 @@
1
+ # router-brain · LLM Routing Brain
2
+
3
+ > **English**: this file · **中文**: [README_CN.md](README_CN.md)
4
+
5
+ > **Separate decision from execution**: a small "brain" model makes decisions (decompose → pick model → dispatch → read feedback); focused workers do one short-context subtask each. Use the right model for the right job, verify across models, fight hallucinations, and save money.
6
+
7
+ > **AI orchestration framework · multi-model router · prompt automation · DeepSeek Harness** — You don't need to know how to write prompts: tell it *what* you want, and the brain decomposes the task, writes the subtask prompts, picks the model, sets the reasoning effort, dispatches workers, reads feedback, and iterates until done.
8
+
9
+ <p align="center">
10
+ <a href="https://github.com/ZzkAItech/router-brain"><img alt="GitHub stars" src="https://img.shields.io/github/stars/ZzkAItech/router-brain?style=flat-square&label=Stars"></a>
11
+ <a href="https://github.com/ZzkAItech/router-brain"><img alt="GitHub forks" src="https://img.shields.io/github/forks/ZzkAItech/router-brain?style=flat-square&label=Forks"></a>
12
+ <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-brightgreen?style=flat-square"></a>
13
+ <a href="https://www.python.org/"><img alt="Python" src="https://img.shields.io/badge/python-3.10+-blue?style=flat-square"></a>
14
+ <a href="https://github.com/ZzkAItech/router-brain/actions"><img alt="tests" src="https://github.com/ZzkAItech/router-brain/actions/workflows/test.yml/badge.svg"></a>
15
+ </p>
16
+
17
+ ---
18
+
19
+ ## Problems it solves
20
+
21
+ ### 🎯 Problem 1: LLMs lose focus in long contexts
22
+
23
+ **Problem**: Shove a whole long task into one model and it must hold the goal, background, progress, and current step all at once. The longer the context, the more it drifts ("lost in the middle").
24
+
25
+ **router-brain's approach**: **Separate decision from execution.**
26
+ - The **brain model only decides** — it sees "goal + current state + who to dispatch". It never touches execution details, so its attention stays on judgment.
27
+ - Each **worker handles one short-context subtask** — it only focuses on the one thing in front of it.
28
+
29
+ > The brain doesn't do the work, so the brain doesn't tire; the worker does one thing, so it doesn't get lost.
30
+
31
+ ### 🌀 Problem 2: Hallucination
32
+
33
+ **Problem**: A single model generates once, with no one checking. In multi-step tasks one hallucinated step corrupts everything downstream.
34
+
35
+ **router-brain's approach**: **Dispatch → feedback → re-dispatch loop.**
36
+ - Brain dispatches → worker finishes → **result returns to the brain**;
37
+ - Brain checks whether it meets the bar; if not, **re-dispatch / switch model** until done or truly unsolvable;
38
+ - Key conclusions are **cross-validated by different models** — one model may fool you, several rarely fool you together.
39
+
40
+ ### 💰 Problem 3: Uncontrollable cost
41
+
42
+ **Problem**: Using an expensive model for everything burns money; using cheap ones for everything can't handle hard tasks.
43
+
44
+ **router-brain's approach**: **Right-size the spend, cheap-first.**
45
+ - The **brain uses a cheap/free model** (it only judges, doesn't need the strongest);
46
+ - **Simple tasks (QA/classify/extract) go direct** — instant reply, no agent boot;
47
+ - **Complex tasks dispatch a worker**, trying cheap → expensive in order;
48
+ - Hooks into **free quotas** automatically.
49
+
50
+ ### 🔗 And deeper problems it solves
51
+
52
+ - **No vendor lock-in**: models are a pluggable pool — switch providers by editing config, not code.
53
+ - **One API down doesn't stop the task**: multi-channel failover + circuit breaker + retry.
54
+ - **Long tasks survive mid-way failures**: subtasks are independent; retry only the failed step.
55
+ - **Quotas stay managed**: cheap-first + healthcheck + auto-degrade low-quota channels.
56
+ - **Context stays small**: decision/execution separation keeps each worker's context short.
57
+ - **Model lifecycle handled**: deprecated models auto-fuse; `sync-free-models` pulls the latest.
58
+ - **Multi-model as a team**: pick the best for each job, cross-validate key results.
59
+
60
+ ### ✍️ Can't write prompts? The brain writes them
61
+
62
+ You only state the **goal** ("refactor this project", "turn this data into a report"). The brain:
63
+ - decomposes into subtasks and **writes each subtask's prompt** (with guardrails, output path, format);
64
+ - **picks the model** — you don't need to know which model is good at what;
65
+ - **sets reasoning effort** — light for simple steps, heavy for deep reasoning.
66
+
67
+ ---
68
+
69
+ ## Architecture in one line
70
+
71
+ ```
72
+ You (goal)
73
+ └─> 🧠 Brain (cheap model, decides only) ──decompose──> 👷 Worker 1 (model A, one task)
74
+ ├──> 👷 Worker 2 (model B, another task)
75
+ └──> 🔁 feedback back; re-dispatch / switch if not OK
76
+ ```
77
+
78
+ - **Decision plane** (this process): classify → pick model → dispatch → read feedback → decide next.
79
+ - **Execution plane** (DeepSeek Harness headless agent): a real agent with tools (bash/files/workspace) actually does the work.
80
+
81
+ > Every worker is a **real agent** — not "ask a question, get text back", but "write files, run scripts, read results".
82
+
83
+ ---
84
+
85
+ ## Quick start
86
+
87
+ ### 1. Install
88
+
89
+ ```bash
90
+ cd router-brain
91
+ python3 -m venv .venv && . .venv/bin/activate
92
+ pip install -e .
93
+ ```
94
+
95
+ Only dependency is PyYAML. Requires **DeepSeek Harness** installed (`dsh` on PATH).
96
+
97
+ ### 2. Configure your model pool
98
+
99
+ router-brain ships **no models/channels** — it's a scheduling framework; you add yours.
100
+
101
+ `config/pool.yaml` is a template. Fill in:
102
+ - **providers**: API channels (base_url + credential key name)
103
+ - **models**: the models you can use (id + channel + cost + kind)
104
+
105
+ Credentials go in `~/.dsh/.credentials.yaml` or same-named env vars; the framework reads them and **never prints keys**. Changes take effect immediately — no restart.
106
+
107
+ ### 3. Run
108
+
109
+ ```bash
110
+ router-brain list-models # see your pool
111
+ router-brain route "write a python script" # routing decision only (no execution)
112
+ router-brain run "turn /tmp data into a report" # route → dispatch → fallback → summary
113
+ ```
114
+
115
+ ### 4. (Optional) Enable the "Router Brain" commander in DeepSeek Harness
116
+
117
+ The repo ships `agent-presets/router-brain/` (commander persona + dispatch skill). Enable it and a new **「路由大脑 / Router Brain」** preset appears in the DSH session picker — it becomes a persistent commander: give it a goal, it decomposes, dispatches, reads feedback, iterates to completion, and gives a final summary.
118
+
119
+ ```bash
120
+ mkdir -p ~/.dsh/.agent-presets
121
+ cp -r agent-presets/router-brain ~/.dsh/.agent-presets/
122
+ # restart dsh web, pick 「路由大脑」 in the new-session picker
123
+ ```
124
+
125
+ > The preset ships only the commander tools (bash/fs/jobs/goal/todo/skill) and no models — brain and workers both use models from *your* `config/pool.yaml`.
126
+
127
+ ---
128
+
129
+ ## Highlights
130
+
131
+ | Capability | Description |
132
+ |---|---|
133
+ | Decision/execution separation | Brain judges, worker executes → fights attention drift |
134
+ | Dispatch-feedback-re-dispatch | Results return; re-dispatch/switch on failure → fights hallucination |
135
+ | Cross-model validation | Key results validated by different models, never self-proven |
136
+ | No hardcoded division | Brain decides allocation at runtime |
137
+ | Multi-channel failover | One model on many channels; auto-switch on limit/shutdown |
138
+ | Retry + degrade + fuse | 429/timeout/5xx retry; fallback chain; circuit breaker |
139
+ | Permanent-error fuse | Deprecated/not-found models fuse instantly |
140
+ | Cheap-first | Defaults to free/low-cost available models |
141
+ | Direct fast-answer | QA/classify/extract reply instantly, no agent boot |
142
+ | Worker channel switch | `worker:false` marks brain-only channels |
143
+ | Millisecond classifier | Deterministic rules, zero cost, zero latency |
144
+ | Program-readable decision | `route` emits JSON for the brain or other programs |
145
+ | Full-task trace | `task_id` through everything; JSON logs, no secrets |
146
+ | healthcheck | Probe the whole pool to see what actually works |
147
+
148
+ ---
149
+
150
+ ## Configuration
151
+
152
+ ### config/routing.yaml
153
+
154
+ ```yaml
155
+ execution:
156
+ max_retries: 2 # transient-failure retries
157
+ max_fallbacks: 4 # model-fallback cap
158
+ timeout_seconds: 600 # per-task timeout
159
+ auto_failover: false # false = stop and let the brain choose
160
+ force_channel: "" # "" = all channels; a name = only that channel
161
+ direct_max_tokens: 2048 # direct-mode token budget
162
+ ```
163
+
164
+ ### config/pool.yaml template
165
+
166
+ ```yaml
167
+ providers:
168
+ my_channel:
169
+ base_url: https://api.example.com/v1
170
+ credential_key: MY_API_KEY # put the key in ~/.dsh/.credentials.yaml
171
+
172
+ models:
173
+ my-model:
174
+ kind: general
175
+ cost: low
176
+ context: 131072
177
+ providers:
178
+ - {channel: my_channel, dsh_provider: my_channel}
179
+ ```
180
+
181
+ ---
182
+
183
+ ## Directory
184
+
185
+ ```
186
+ router-brain/
187
+ ├── config/
188
+ │ ├── pool.yaml your model pool (template)
189
+ │ └── routing.yaml routing rules + execution params
190
+ ├── agent-presets/
191
+ │ └── router-brain/ DSH preset (copy to ~/.dsh/.agent-presets/ to use)
192
+ ├── src/router_brain/
193
+ │ ├── config.py config + pool/channel/degrade management
194
+ │ ├── router.py model selection
195
+ │ ├── degrade.py retry + degrade + circuit breaker
196
+ │ ├── executor.py agent/direct execution
197
+ │ ├── llm_api.py direct-mode client (error classification)
198
+ │ └── cli.py CLI entry
199
+ ├── tests/ unit tests (fully offline)
200
+ ├── CONTRIBUTING.md contribution guide
201
+ ├── CHANGELOG.md changelog
202
+ ├── LICENSE MIT
203
+ └── README.md this file
204
+ ```
205
+
206
+ ## Security
207
+
208
+ - Never reads-and-prints any key; direct mode resolves once, agent mode never touches keys.
209
+ - Worker subprocess cwd = `--cwd`; file permissions follow DSH sandbox policy.
210
+ - healthcheck consumes real API quota (~a dozen tiny calls per full run).
211
+ - Keys never appear in logs or output.
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "router-brain"
7
+ version = "1.1.0"
8
+ description = "模型路由大脑:分析任务 → 从模型池选模型 → 派给 DeepSeek Harness headless agent 执行 → 失败降级重试 → 汇总结果"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "router-brain contributors" }]
13
+ keywords = ["llm", "routing", "agent", "deepseek-harness", "model-router", "multi-model"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Operating System :: OS Independent",
17
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
18
+ ]
19
+ dependencies = ["PyYAML>=6.0"]
20
+
21
+ [project.optional-dependencies]
22
+ dev = ["pytest>=7.0"]
23
+
24
+ [project.scripts]
25
+ router-brain = "router_brain.cli:main"
26
+
27
+ [tool.setuptools]
28
+ package-dir = { "" = "src" }
29
+
30
+ [tool.setuptools.packages.find]
31
+ where = ["src"]
32
+
33
+ [tool.pytest.ini_options]
34
+ testpaths = ["tests"]
35
+ addopts = "-q"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,15 @@
1
+ """router-brain: 模型路由大脑。
2
+
3
+ 决策面(本进程)负责分类 + 选模型 + 编排;
4
+ 执行面(DeepSeek Harness headless agent)负责真正动手干活。
5
+ """
6
+
7
+ __version__ = "1.1.0"
8
+
9
+ # 导出核心类
10
+ from .config import Config
11
+ from .degrade import Runner
12
+ from .classifier import Classifier
13
+ from .router import Router
14
+
15
+ __all__ = ["Config", "Runner", "Classifier", "Router", "__version__"]
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())
@@ -0,0 +1,33 @@
1
+ """规则式任务分类器:任务文本 → task_type。
2
+
3
+ 确定性、零成本、毫秒级。关键词表来自 routing.yaml 的 classifier 段。
4
+ 命中多个类型时按关键词在表里的出现顺序取第一个命中(表顺序即优先级)。
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from .config import Config
9
+
10
+
11
+ class Classifier:
12
+ def __init__(self, cfg: Config) -> None:
13
+ self._keywords = cfg.keywords
14
+ self._ordered_types = list(self._keywords.keys())
15
+ # 预先将所有关键词转为小写,避免每次循环都调用 lower()
16
+ self._keywords_lower = {
17
+ task_type: [kw.lower() for kw in keywords]
18
+ for task_type, keywords in self._keywords.items()
19
+ }
20
+
21
+ def classify(self, task: str, hints: str = "") -> str:
22
+ if not task or not task.strip():
23
+ raise ValueError("任务不能为空")
24
+ text = task + " " + (hints or "")
25
+ text_lower = text.lower()
26
+ for task_type in self._ordered_types:
27
+ for kw in self._keywords_lower.get(task_type, []):
28
+ if kw in text_lower:
29
+ return task_type
30
+ # 带图片提示强制视觉
31
+ if any(t in text_lower for t in ("图片", "截图", ".png", ".jpg", ".jpeg", ".webp", "image")):
32
+ return "vision"
33
+ return "fallback"