Add per-sub-agent provider routing#3969
Conversation
|
Thanks @heyparth1 for taking the time to contribute. This repository is observing a maintainer-managed PR intake gate in dry-run mode, so this pull request is staying open. This note helps maintainers prepare the allowlist before any enforcement is considered. Please read |
|
Thanks @JayBeest! Yes, this pins any sub-agent to any configured provider/model (not just local vs cloud); smart/keyword routing is a good follow-up but out of scope here. |
|
Thanks for the pointer — I've reshaped the PR description to follow the repository's PR template (Summary / Testing / Checklist) and re-verified the contribution shape from CONTRIBUTING.md: single-purpose scope, tests included, docs updated. I also ran the template's exact checks ( |
|
Thanks @heyparth1. Explicit per-sub-agent provider routing is interesting and the reported local verification is appreciated, but I am leaving it out of 0.8.67 because it is currently blocked and touches provider/model routing semantics for sub-agents. I am cutting 0.8.67 soon; please keep this warm for 0.8.68 after a rebase so we can review the routing behavior and docs without rushing it. |
|
Thanks for this @heyparth1 — it's genuinely well done: Heads up on timing: we're actively reworking the sub-agent fleet/routing system right now (the #3932–#3935 cluster — role taxonomy, model classes, per-role routing, wizard-authored profiles). Your PR lands new per-role routing machinery in the same spawn/resolution path that redesign is about to reshape, and I'd rather not have us design per-role provider routing twice and then reconcile a merge conflict. So I'm going to hold this and land it aligned with the new fleet system in v0.8.68, rather than merge it into the current path now. Moving it to the v0.8.68 milestone and keeping it open — nothing about the approach here is rejected, it's a sequencing call so this routing slots cleanly into the new taxonomy. I'll revisit it (with credit) once the fleet work is out. Appreciate the contribution. Generated by Claude Code |
|
Great update, thanks @Hmbown! Delaying to align with the fleet redesign (#3932–#3935) is clearly the right move—better to build on a stable foundation than layer new routing on a path that's about to change. I'm genuinely impressed with how quickly @heyparth1 turned this around. The implementation matches exactly what I had in mind with the original issue, and the feedback on the approach is really encouraging. On the broader direction: I'd love to help scope or discuss what comes after this foundation. A few areas I'm thinking about: These all build on the explicit routing this PR establishes. Where's the best place to continue that conversation? I'm guessing just opening new issues as they crystallize (like I did with this one) is the right approach, but let me know if there's a design thread or discussion space I should be watching. Thanks again to everyone involved—this is shaping up to be a really powerful foundation. Co-authored by my Chinese Friend (DeepSeek) |
|
Since we're delaying to align with the fleet redesign, I want to suggest we broaden the scope of the new SubagentDefinition struct just slightly—so it natively supports both routing AND environmental constraints. This would unify my explicit routing request (#3965) with the constitutional crisis (#4032) in one clean architecture. Proposed struct additions: How they work together to fix the Constitution bug: [subagents.strict_analyzer] The router picks the cheapest local model (solving #3965), while the orchestrator strips the disabled tools from the API schema before the LLM even sees them. Why this is better than just a constraint: flag in SKILL.md: Cross-linking: This is the architectural fix for #4032. I'll cross-link this comment there so the constitutional crisis thread knows this is coming down the pipeline. Co-authored by my Chinese Friends (DeepSeek) |
|
Sounds good @Hmbown — holding for v0.8.68 to align with the fleet redesign (#3932–#3935) makes sense, and I'm happy to rebase onto the new taxonomy once it lands; I've updated the PR description to reflect the new target and will keep it warm. @JayBeest, I'd keep |
|
Agree completely - correction / refinement on my earlier suggestion: After digging deeper into the architecture, I now think tool_restrictions doesn't belong in the routing config (SubagentRouteConfig). It fits much better in the Fleet configuration layer (#3932–#3935) as a durable capability boundary, enforced at runtime via the existing Tool Registry / gate chain (filter_tool_catalog_for_gates). I've opened a new issue to scope out the runtime hook point specifically: #4042. Let's keep the routing PR focused purely on provider/model assignment. |
|
Thanks @JayBeest — agreed on all counts, and #4042 is the right home for tool restrictions as a fleet-layer capability boundary rather than routing config. I've updated the PR description's scope section to point there, so this PR stays purely provider/model assignment and remains ready to rebase onto the fleet taxonomy for v0.8.68. |
Summary
Adds explicit per-sub-agent provider routing (#3965): a new
[subagents.routes.<role>]config table pins a sub-agent role or type to aspecific provider — and optionally a model — so one session can, for example,
run
explore/formatchildren on a local LM Studio endpoint whilegeneralruns on DeepSeek, with no manual provider switching.
How it works:
config.rs: newSubagentRouteConfig+routestable onSubagentsConfig,exposed via
Config::subagent_provider_routes()(lowercased keys, trimmedvalues). Same role/type/
defaultkey precedence as[subagents.models].tools/subagent/mod.rs:SubAgentRuntimecarries anOption<Arc<SubagentProviderRouting>>bundle (routes + config snapshot).At spawn, a matching route builds the child's client through the existing
v0.8.67: Ship configured-provider route manager for /provider and /model #3830 route resolver (
route_runtime::resolve_runtime_route+DeepSeekClient::from_candidate) — the same path/providerswitchinguses — and swaps it into the child runtime. The routed client drops with
the child; no new auth/client-lifecycle machinery.
core/engine.rs: routing bundle is rebuilt fromapi_configat eachruntime construction, so mid-session
/providerchanges are picked up.the unchanged legacy path. A per-call explicit
modelstill wins over theroute's model; both validate against the routed provider. A route naming a
provider that is neither built-in nor a
[providers.<name>]custom entryfails that spawn with a clear error instead of silently falling back to
DeepSeek.
docs/SUBAGENTS.md: new "Per-role provider routes (Per-sub-agent provider assignment (explicit routing) + LM Studio support #3965)" section with theLM Studio example above.
Scope boundary
This PR stays single-purpose: explicit provider/model assignment only.
Intentionally out of scope, as follow-ups once the fleet redesign settles the
taxonomy:
covers LM Studio; the missing piece was routing, which this PR adds.
cheapest/fastest/ capability tiers) andkeyword or complexity-based auto-routing — these belong to the new fleet
SubagentDefinitiondesign (fleet(setup): wizard "Start" writes nothing and dead-ends; /fleet status doesn't show the ledger the copy promises #3935) so per-role routing isn't designedtwice. The explicit
provider+modelroute here is the primitive thosecan resolve onto.
tool_restrictions— consensus in review is that capabilityboundaries live in the fleet configuration layer, not the routing config;
now tracked separately in feat: Environment-level tool sandboxing for sub-agents (enforce tool_restrictions) #4042 (relates to Codewhale not following the constitution #4032).
Closes #3965
Testing
cargo fmt --all -- --checkcargo clippy --workspace --all-targets --all-featurescargo test --workspace --all-featuresNew regression tests (all green; suite: 5727 passed / 0 failed):
config::tests::subagent_provider_routes_parse_and_normalize— TOML parsingand key/value normalization for
[subagents.routes].tools::subagent::tests::role_provider_route_builds_client_on_routed_provider— the issue's headline scenario: parent on DeepSeek,
explorerouted to anLM Studio-style custom provider; asserts the routed client binds to
http://localhost:1234/v1with the route's model while the parent client isuntouched.
tools::subagent::tests::role_without_provider_route_inherits_parent—unrouted roles keep the legacy inherit behavior.
tools::subagent::tests::provider_route_with_unknown_provider_fails_clearly— unknown provider is rejected with an error naming it and pointing at the
[providers.<name>]config path.Checklist
docs/SUBAGENTS.mdsection + doccomments on all new config/runtime surfaces)
spawn path, and engine wiring only)
a harvest — original work for Per-sub-agent provider assignment (explicit routing) + LM Studio support #3965)