feat(profiles): route sub-agent requests to a profile-level subagent_target#112
Conversation
|
WalkthroughThe change adds optional ChangesSub-agent Override Routing
Estimated code review effort: 4 (Complex) | ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/routing_algorithms/overview.md`:
- Around line 91-95: Update the routing behavior description near the recognized
sub-agent signals and its corresponding section to state that an explicit
x-switchyard-is-subagent: false header takes precedence over Codex or Claude
agent signals and preserves normal profile routing, while true continues to
enable direct passthrough.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 24d05bd0-b6b4-41b2-b89f-f648c12ece25
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock,!Cargo.lock
📒 Files selected for processing (13)
.agents/skills/switchyard-lib-core/SKILL.mdcrates/switchyard-components-v2/src/config/parsing.rscrates/switchyard-components-v2/src/config/resolving.rscrates/switchyard-components-v2/tests/config.rscrates/switchyard-py/Cargo.tomlcrates/switchyard-py/src/profile_bindings/mod.rscrates/switchyard-py/src/profile_bindings/typed.rsdocs/routing_algorithms/overview.mdswitchyard/lib/profiles/loader.pyswitchyard/lib/profiles/subagent_override.pyswitchyard_rust/profiles.pyswitchyard_rust/profiles.pyitests/test_subagent_routing.py
Shouldn't we fix |
|
@linj-glitch can we have an implementation of this in libsy |
|
@messiaen Agreed in spirit — implemented in 29015c9, with one refinement: the comment bundles two things that I think deserve different treatment. Fixed in Kept out of One intentional behavior consequence: Coverage: 2 new protocol tests (explicit-flag decides without a parent header; |
|
@messiaen libsy implementation landed in a7c4a57 (coordinated with @GRClark — building blocks kept small so it composes with the fallthrough work when that lands). It's a combinator, mirroring the profile-envelope shape one level down: let algorithm = SubagentOverride::new(inner_algorithm, worker_target);
Also exposed through the minimal Python surface as Coverage: 3 Rust tests (no-metadata delegation, Claude-lineage and Codex 🤖 Generated with Claude Code |
…target Signed-off-by: Lin Jia <linj@nvidia.com>
…t work policy Signed-off-by: Lin Jia <linj@nvidia.com>
…o a fixed target Signed-off-by: Lin Jia <linj@nvidia.com>
Claude Code only sends x-claude-code-agent-id for child agents; root agents omit it. Change the predicate from an agent-id/session-id inequality check to agent.is_some(), matching the official contract and handling agent-id-only requests that the old check silently missed. Remove CODEX_PARENT_THREAD_ID_PATH and CODEX_PARENT_THREAD_ID_HEADER from SUBAGENT_SIGNAL_PATHS and drop the `parent.is_some()` inference arm from parse_sub_agent. Codex parent-thread-id is correlation data, not a routing signal; the old code created a false-positive path where a kindless Codex turn with only a parent thread ID routed as sub-agent work. Parent ids are still captured in Metadata for observability via HEADER_CONFIG. Add tests for the corrected cases and document x-switchyard-is-subagent: false override behavior in the routing overview. Signed-off-by: Lin Jia <linj@nvidia.com>
a9b0804 to
afde9cc
Compare
…trailers Signed-off-by: Lin Jia <linj@nvidia.com>
…ee bugs Remove correlation-only headers (Relay, Dynamo, OpenCode) from routing signals; add `is_delegated_work` field derived from raw harness signals independent of the operator `x-switchyard-agent-kind` label; add Rust `SubagentOverrideProfile` in components-v2 with full stats recording so Rust-profiled deployments flow through the Rust stats pipeline. Signed-off-by: Lin Jia <linj@nvidia.com>
c62b745 to
1e01762
Compare
Summary
Adds envelope-level sub-agent routing per the sub-agent routing design: any profile config may name an optional
subagent_target, and requests that carry a recognized delegated sub-agent signal bypass the profile's routing and run as a direct passthrough to that target. Everything else — including profiles without the field — behaves exactly as today.This keeps a sub-agent loop on one intentional, cache-compatible target and honors an explicit orchestrator-vs-worker model split, instead of re-routing every worker turn through the profile's router.
How it works
subagent_targetis consumed inSerializedProfileConfig::deserializeexactly liketype, so profile-owned bodies (whichdeny_unknown_fields) never see it and the field works for every profile type, Rust- or Python-defined. An unknown target reference fails atresolve()/ load time — a startup configuration error.is_subagent_request(headers)pyfunction reuses the canonical harness header normalization fromswitchyard-protocol(Metadata::from_headers, feat(switchyard-protocol): add common utility to hydrate Metadata from headers #92) and layers the routing policy on top:x-openai-subagent: collab_spawn/reviewand Claude Code agent lineage route as sub-agent work;compact,memory_consolidation) and unrecognized kinds stay on normal profile routing;x-switchyard-is-subagentdecides directly, in both directions.subagent_targetinSubagentOverrideProfile, which selects per request between the wrapped profile and aPassthroughProfileConfigbranch for the resolved target. It forwards the full context-aware profile surface (so stats and route-selection context propagation are preserved) and never rewrites the request/response. An override-branch failure surfaces as a normal target error — it is not silently re-routed through the main router.Policy note: the work-vs-maintenance kind filter lives in the binding, not the protocol crate, so the canonical
Metadata::from_headerssemantics are unchanged.Testing
cargo testgreen forswitchyard-components-v2,switchyard-py,switchyard-protocol; clippy and fmt clean.tests/test_subagent_routing.py): detection matrix, loader wrapping for both a Rust (passthrough) and a Python (header-routing) profile against a mock upstream, maintenance-kind fall-through, startup rejection of unknown targets on both profile kinds, lifecycle spanning both branches, and no-fallback-on-override-failure.uv run ruff check .,uv run mypy switchyard(strict), and the full suite pass: 2026 passed. The only failures are 3 pre-existingtests/e2e/cases that 401 against an external LiteLLM proxy (environmental, unrelated).docs/routing_algorithms/overview.md) and theswitchyard-lib-coreskill updated alongside the code.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
subagent_targetrouting for profiles.Documentation
Tests