Skip to content

feat(agent): smart model routing (pre-turn task-difficulty router) - #20327

Closed
crogers2287 wants to merge 1 commit into
NousResearch:mainfrom
crogers2287:ash/smart-model-router
Closed

crogers2287 wants to merge 1 commit into
NousResearch:mainfrom
crogers2287:ash/smart-model-router

Conversation

@crogers2287

Copy link
Copy Markdown

Summary

Adds a deterministic, turn-scoped router that picks the right model before each user turn starts, complementing the existing fallback chain (which handles provider failure mid-turn). Two modes, auto-detected from config:

  • local-first — primary is a fast/cheap local model; hard tasks escalate to a smart cloud model.
  • smart-primary — primary is a strong cloud model; simple tasks demote to a configured cheap/local model.

When smart_model is omitted, the first fallback_providers entry is used as the smart target so a single config can drive both provider failover and difficulty escalation.

Design

  • New pure module agent/smart_model_routing.py — heuristic classifier (length / keywords / phrases / code-fence / traceback / multi-question), mode resolution, decide_route(). No network, no SDK imports.
  • AIAgent._maybe_apply_smart_routing() runs at the top of run_conversation() after _restore_primary_runtime(). Inline runtime swap mirrors the bookkeeping in _try_activate_fallback (resolve client, determine api_mode, refresh prompt-cache + context engine), and sets _fallback_activated=True so the next turn restores primary the same way fallback does.
  • New smart_model_routing config block with the same provider/model/base_url/api_key shape as fallback entries. Disabled by default; bad config logs and stays on primary.
  • Wired through cli.py (both AIAgent construction sites) and gateway/run.py (_load_smart_model_routing() + both construction sites).

Config

```yaml
smart_model_routing:
enabled: true
mode: auto # auto | local-first | smart-primary
max_simple_chars: 160
max_simple_words: 28
cheap_model:
provider: custom
model: fast-local-model
base_url: http://fred:9069/v1
api_key: local
smart_model:
provider: openrouter # if omitted, fallback_providers[0] is used
model: anthropic/claude-sonnet-4
extra_hard_keywords: [permitting, rezoning]
```

Mode auto-detection (when `mode: auto` or unset):

  • only `smart_model` configured → local-first
  • only `cheap_model` configured → smart-primary
  • both configured → local-first when primary provider is local-like (`custom`, `ollama`, `vllm`, `lmstudio`, `llamacpp`, `local`, `localhost`, `fred`, …), else smart-primary
  • neither → routing effectively disabled

Test plan

  • 39 unit tests on the pure decision module (`tests/agent/test_smart_model_routing.py`) — disabled config, both modes, fallback-as-smart, invalid targets, mode auto-detect, dataclass immutability, never-raises-on-garbage.
  • 9 runtime tests with stubbed AIAgent + mocked `resolve_provider_client` (`tests/run_agent/test_smart_model_routing_runtime.py`) — including a guard that fails the test if any `httpx.Client.send` call is made.
  • No HTTP and no local model endpoints touched anywhere in the test suite.
  • Smoke-test on a real config when GPU is available (deferred per user request).

Docs

  • `website/docs/user-guide/features/smart-model-routing.md` — full feature page.
  • Cross-link added in `website/docs/user-guide/configuration.md`.
  • `smart_model_routing` added to `_KNOWN_ROOT_KEYS` in `hermes_cli/config.py` so the config validator accepts the new block.

Risks / follow-ups

  • Inline runtime swap duplicates ~80 lines of `_try_activate_fallback`'s bookkeeping. A future refactor could extract a shared `_apply_runtime(target)` helper.
  • Heuristic is deterministic and intentionally simple. Tunable via `max_simple_chars`, `max_simple_words`, and `extra_hard_keywords`. An LLM classifier was scoped out of the MVP.

🤖 Generated with Claude Code

Adds a deterministic, turn-scoped router that picks the right model
before each user turn starts. Local-first mode escalates hard tasks to
a smart cloud model; smart-primary mode demotes simple tasks to a cheap
local model. Auto-detects mode from config and primary provider.

The decision module (agent/smart_model_routing.py) is pure and tested
in isolation. The runtime swap in AIAgent mirrors the existing fallback
client/api_mode/cache bookkeeping and reuses _restore_primary_runtime
for turn-scoped restoration. When smart_model is omitted, the first
fallback_providers entry is used, so a single config can drive both
provider failover and difficulty escalation.

Disabled by default and on bad config; existing fallback semantics are
preserved.

Tests: 48 passing (39 unit + 9 runtime). No HTTP calls, no local model
endpoints touched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/gateway Gateway runner, session dispatch, delivery comp/cli CLI entry point, hermes_cli/, setup wizard labels May 5, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

Competing implementation with #18930 — both add pre-turn smart model routing. This PR adds local-first/smart-primary modes with a heuristic classifier; #18930 takes a simpler approach. Related tracking: #8462 (/model override conflict).

@teknium1

Copy link
Copy Markdown
Collaborator

Closing as superseded by #12732.

Triage notes (medium confidence):
Merged PR #12732 (2026-04-20) 'refactor: remove smart_model_routing feature' explicitly removed this feature direction; AGENTS.md:347 still lists the config key as historical but no implementation file exists. Re-adding 1275 LOC contradicts project direction.

Thanks for the contribution — the underlying problem this PR addresses has been resolved by the linked PR on current main. If you believe this was closed in error, please comment and we'll reopen.

(Bulk-closed during a CLI PR triage sweep.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants