Repository navigation
[FEATURE]: Dynamic model selection for subagents via Task tool #6651
Description
Feature hasn't been suggested before.
- I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
Problem
When a primary agent invokes a subagent via the Task tool, it cannot dynamically control which model the subagent uses. The current model is determined by:
- The agent's pre-configured model (in
opencode.json) - Fallback to the parent session's model
This creates friction in two scenarios:
- Users create duplicate agents with identical prompts just to vary the model -
explore-quick,explore-standard,explore-advancedall pointing to the same prompt file. - The primary agent cannot assess task complexity and select an appropriate model. A trivial file search uses the same model as complex architectural analysis, wasting cost or capability.
Solution A: Global Model Tiers
Add a model_tier parameter to the Task tool with three values: quick, standard, advanced. Users configure tier-to-model mappings globally.
Configuration
{
"model_tiers": {
"quick": { "model": "anthropic/claude-haiku-4-5" },
"standard": { "model": "anthropic/claude-sonnet-4-5" },
"advanced": { "model": "anthropic/claude-opus-4-5" }
}
}Task Tool Usage
Task(
description = "Find config files",
prompt = "List all JSON config files in the project",
subagent_type = "explore",
model_tier = "quick",
)Why Not Raw Model IDs?
An alternative would expose a model parameter accepting raw model IDs directly. This has drawbacks:
- Training cutoff: LLM may not know newer models released after its training date
- Model proliferation: Providers like OpenRouter expose 100+ models - either bloat the tool description or provide no guidance
- No validation: LLM could specify unavailable models; errors surface only at runtime
The tier abstraction solves these: the LLM assesses task complexity (which it can do), mappings are user-configured and guaranteed valid, and token cost is fixed (3 enum values).
Solution B: Agent-Level Model Tiers
Add the same model_tier parameter, but configure tier-to-model mappings per-agent instead of globally.
Configuration
{
"agent": {
"explore": {
"model_tiers": {
"quick": { "model": "anthropic/claude-haiku-4-5" },
"standard": { "model": "anthropic/claude-sonnet-4-5" },
"advanced": { "model": "anthropic/claude-opus-4-5" }
}
},
"code-review": {
"model_tiers": {
"quick": { "model": "anthropic/claude-sonnet-4-5" },
"standard": { "model": "anthropic/claude-opus-4-5" },
"advanced": { "model": "anthropic/claude-opus-4-5" }
}
}
}
}Task Tool Usage
Task(
description = "Security-focused review",
prompt = "Review auth.ts for vulnerabilities",
subagent_type = "code-review",
model_tier = "advanced",
)This approach allows agent-specific mappings - quick for explore (simple file search) might map to Haiku, while quick for code-review might still need Sonnet.
Solution C: Unified Approach
Combine both solutions with layered resolution. Same model_tier parameter, but agent-level model_tiers override global tiers when defined.
Configuration
{
"model_tiers": {
"quick": { "model": "anthropic/claude-haiku-4-5" },
"standard": { "model": "anthropic/claude-sonnet-4-5" },
"advanced": { "model": "anthropic/claude-opus-4-5" }
},
"agent": {
"code-review": {
"model_tiers": {
"quick": { "model": "anthropic/claude-sonnet-4-5" }
}
}
}
}Task Tool Usage
Same as Solutions A and B - the parameter is identical.
Resolution
explorewithmodel_tier="quick"-> no agent override -> uses global tier -> Haikucode-reviewwithmodel_tier="quick"-> uses agentmodel_tiers-> Sonnet (override)code-reviewwithmodel_tier="advanced"-> no agent override -> falls back to global tier -> Opus
Model Selection Hierarchy
All solutions extend the existing hierarchy:
1. Agent's configured model -> Explicit agent.model wins (tier ignored)
2. Agent-level model_tiers[tier] -> If defined (Solution B/C)
3. Global model_tiers[tier] -> If defined (Solution A/C)
4. Parent session's model -> Fallback
Implementation Notes
Solution A requires:
- Task tool: add
model_tier: z.enum(["quick", "standard", "advanced"]).optional() - Config: add
model_tiers: { quick?: { model: string }, ... } - Model resolution: check global tier mapping before session fallback
Solution B requires:
- Task tool: add
model_tier: z.enum(["quick", "standard", "advanced"]).optional() - Agent config: add
model_tiers: { quick?: { model: string }, ... } - Model resolution: check agent's tier mapping before session fallback
Solution C requires:
- All of the above
- Model resolution: check agent tier first, then global tier, then session fallback
Future Extensibility
The object structure for tier configuration allows future enhancements without breaking changes:
{
"model_tiers": {
"quick": {
"model": "anthropic/claude-haiku-4-5",
"temperature": 0.2,
"max_tokens": 4000
},
"advanced": {
"model": "anthropic/claude-opus-4-5",
"temperature": 0.7
}
}
}Potential future additions:
temperature- override default temperature for tiermax_tokens- limit output tokens for cost controltop_p- adjust sampling for tiertimeout- per-tier timeout settings
This is out of scope for the initial implementation but the object structure supports it.
Would any of these approaches be welcome? Is there a preferred direction, or alternative solutions already considered?
Activity
github-actions commentedon Jan 2, 2026
This issue might be a duplicate of existing issues. Please check:
Feel free to ignore if these don't address your specific case.
[-][FEATURE] Dynamic model selection for subagents via Task tool[/-][+][FEATURE]: Dynamic model selection for subagents via Task tool[/+]m10rten commentedon Jan 7, 2026
This is a nice feature, could save costs doing something simple versus some task that requires the full agent capacity.
However it would be even more useful if a primary agent calling subagents controls this.
mcking-07 commentedon Jan 8, 2026
@m10rten Could you clarify what you mean by
The feature I'm proposing DOES let the primary agent control the model via the
model_tierparameter on the Task tool.Are you asking for the primary agent to decide the model and provider ID? That won't be viable for reasons already mentioned in the issue (training cutoff, model proliferation, no validation, etc.)"
m10rten commentedon Jan 8, 2026
More that in the instructions you could say: call @ junior-developer or @ senior-developer, but both would do the same in a different model.
So why not have the caller control the model?
Just an idea...
mcking-07 commentedon Jan 15, 2026
Update
I implemented Solution C and have been using it extensively on my local dev environment for the past two weeks.
Recent Discovery: Model Variants
While rebasing onto the latest dev, I discovered the Model Variants feature was added in parallel. After analyzing it, I found that our approaches are highly complementary.
My original design used an object structure for tiers. This structure is already extensible for variants. We simply need to add
variantas an optional field:{ "model_tiers": { "quick": { "model": "openai/gpt-5.2", "variant": "low" }, "standard": { "model": "openai/gpt-5.2", "variant": "medium" }, "advanced": { "model": "openai/gpt-5.2", "variant": "high" } } }Per-agent overrides in
opencode.jsoncan also include variants:{ "agent": { "explore": { "model_tiers": { "quick": { "model": "openai/gpt-5.2", "variant": "high" } }, "variant": "medium" } } }Priority Order
Model Resolution:
agent.model- explicit agent configagent.model_tiers[tier]?.model- per-agent tier overrideconfig.model_tiers[tier]?.model- global tier configVariant Resolution:
agent.variant- explicit agent configagent.model_tiers[tier]?.variant- per-agent tier variantSummary
The variant feature validates the need for fine-grained model control that this feature request addresses.
I'm happy to rebase and complete the implementation.
dpearson2699 commentedon Jan 21, 2026
Adding another concrete use case for per-subagent model selection at spawn time.
Context / real-world driver (GSD model profiles)
I’m working with gsd-opencode (an OpenCode adaptation of the “get-shit-done” workflow) and trying to add “model profiles” where different roles use different models (planner vs executor vs verifier), similar to the original Claude Code setup.
Why call-time model selection matters
In the Claude Code GSD workflow, the orchestrator reads a project-local config (e.g.
.planning/config.jsonwithmodel_profile: quality|balanced|budget) and then spawns different subagents with different models in the same run (e.g. planning = higher quality, execution = balanced, verification = cheaper).In OpenCode today,
taskinvocations can’t cleanly replicate that pattern because the Task tool schema does not allow specifying a model at call time. The model used by a Task/subagent is effectively:agent.model, otherwiseThat forces awkward workarounds (duplicate agents pinned to different models, or rewriting agent definitions between runs) instead of a clean orchestrator-driven “profile” switch.
Minimal request
Add an optional way to choose the subagent model at Task spawn time (e.g.
modelas a string likeanthropic/...or an enummodel_tier), so orchestrator-style workflows (like gsd-opencode) can select different models per subagent without duplicating agents.Suggested resolution order:
model/model_tier, use it.agent.model, use it.This preserves current behavior by default.
enesgur commentedon Jan 21, 2026
With this feature, we can make multi-model usage much more effective. For example, we can use Codex for planning, Claude for coding, and GLM for reviews. This also reduces token consumption.
mcking-07 commentedon Jan 30, 2026
update
Implemented in PR #11377
This follows the unified approach (Solution C) from the issue - added
model_tierparameter to Task tool withquick/standard/advancedtiers. You can configure tier-to-model mappings globally or per-agent, with agent-level overriding global.Also includes variant support as discussed in #6651 (comment) - tier configs can optionally specify
variantfor models that support it.Note on related PRs:
These are complementary - agents can have default variants while still allowing tier-based overrides via Task tool.
Steffen025 commentedon Feb 3, 2026
Strong support + Multi-Provider Research use case
This feature directly enables my primary use case: Multi-Provider Research.
The Problem Today
I have custom agents configured for different AI providers:
PerplexityResearcher→model: perplexity/sonar(real-time web search)GeminiResearcher→model: google/gemini-2.5-pro(multi-perspective)ClaudeResearcher→model: anthropic/claude-sonnet-4-5(deep analysis)GrokResearcher→model: xai/grok-3(contrarian viewpoints)The orchestrator should spawn these agents using their configured models to get genuinely different perspectives from different providers. Currently, they ALL run on Claude because the Task tool ignores the agent's
modelfield.Why Tiers Won't Fully Solve This
The
model_tierapproach (quick/standard/advanced) is great for cost optimization within a single provider. But my use case needs provider diversity, not just model size variation.Suggestion: Extend PR #11377
Could the tier config also support provider routing? For example:
{ "model_tiers": { "quick": { "model": "anthropic/claude-haiku-4-5" }, "standard": { "model": "anthropic/claude-sonnet-4-5" }, "advanced": { "model": "anthropic/claude-opus-4-5" }, "realtime": { "model": "perplexity/sonar-pro" }, "multimodal": { "model": "google/gemini-2.5-pro" } } }Or alternatively, respect the agent's configured
modelfield when no tier is specified?Summary
modelrespected as fallbackmcking-07 commentedon Feb 4, 2026
@Steffen025 The PR already supports multi-provider configurations, there's no restriction to a single provider. The model field in tier configs accepts any model ID from any provider.
You can configure tiers with mixed providers like this:
{ "model_tiers": { "quick": { "model": "google/gemini-3-pro" }, "standard": { "model": "openai/gpt-5.2" }, "advanced": { "model": "anthropic/claude-opus-4-5" } } }And regarding your other suggestion:
Yes, this is exactly how this works — the hierarchy is agent's explicit model → agent-level model_tiers[tier] → global model_tiers[tier] → parent session's model.
The current implementation uses quick/standard/advanced as the enum values to keep the LLM's decision space small (it only needs to assess task complexity), but the infrastructure supports extension. If there's demand, we could consider making tiers configurable or adding more enum values in a follow-up enhancement.
Your multi-provider research use case should work perfectly with the current implementation - just configure each tier with whatever provider/model combo you need.
unomaas commentedon Feb 10, 2026
Bumping this with an upvote! Seems like the best implementation for something that a lot of people are requesting. Good work man, hope it gets merged in soon!
Steffen025 commentedon Feb 10, 2026
Quick update from our side: After our earlier comment about multi-provider research, we discovered that our actual issue was a separate config bug — agent frontmatter fields (
description,tools, etc.) were leaking into LLM API requests and causing provider rejections. We filed that separately as PR #12967.So to be clear: model tiers were never the problem for us. We actually built our entire agent system around
model_tier(Solution C) in a local dev build of PR #11377, and it works extremely well. We're running 15 agents across 5 providers (Anthropic, Zen/OpenRouter, Perplexity, xAI, Google) with per-agent tier mappings, and the orchestrator's ability to dynamically selectquick/standard/advancedbased on task complexity has been a game-changer for cost control.Strongly in favor of merging #11377. The tier abstraction is the right design — simple for the LLM to reason about, fully user-configurable, and it composes perfectly with multi-provider setups. Great work @mcking-07, this is a well-thought-out feature.
22 remaining items
adambak033 commentedon May 28, 2026
Bump as well, sooooo needed! ✨
trevor-vaughan commentedon May 28, 2026
Fuzzy matching would also be nice. When I have access to multiple versions (or heck one version) of
sonnet. I want to be able to just saysonnetand have it pick the latest model. Pinning makes portability difficult.I'd also like a fallback list in case I'm switching between providers (Claude vs Google vs GPT etc...).
Frankly, fuzzy matching would be nice everywhere but it's critical for portable subagents.
xintron commentedon May 28, 2026
Or better, sort the matches in groups, just like the original list. A favorited model above the recent model above the general list of all models.
It would be so much nicer to type
sonnetand get the model you have favorited on top. Right now, it's the oldest model due to how the sorting works on plain strings.mcking-07 commentedon May 31, 2026
Appreciate the engagement from everyone! Quick status: PR #11377 is still open, waiting on maintainer review.
@trevor-vaughan @xintron — you're raising a distinct (and valid) concern about model resolution UX (fuzzy matching, sorting, favorites), which is orthogonal to the tier-based selection this PR implements. The tier abstraction solves "which model does this subagent use" at the config/schema level. It's the what. What you're describing is how the user/session picks which model goes into that tier in the UI/CLI.
@xintron the sorting-by-favorites suggestion specifically feels like a UX improvement for the model picker (⌘T or
model:input), not something the Task tool schema needs to worry about.I'll keep this issue scoped to the Task tool API (
model_tierparameter + config resolution). If any of you want to champion the fuzzy matching or model picker sorting, I'd +1 those as follow-ups.Ylandolsi commentedon Jul 10, 2026
bump !
connor-kress commentedon Jul 11, 2026
#34947 seems to be a more up to date implementation of this.
RajatGarga commentedon Aug 22, 2026
Bump!
balboah commentedon Sep 15, 2026
this is something I've used a lot coming from claude code as well, sometimes the parent session decides to use a more capable model instead of the default model for a sub agent definition. In open code I might want tot ell it to use a different provider than the default because of quota reasons as well.
I'm personally more fond of the tool have the ability to pass a "model" param (and "variant"?) to essentially override the sub agent definition temporarily, than to first also define a list of "tiers".
chenhz01 commentedon Sep 17, 2026
We run a tiered model-routing setup in production and Solution C is the right shape — raw model IDs in the tool schema age badly for exactly the reasons listed (training cutoff, model proliferation, no validation), while a 3-enum tier keeps the decision space auditable.
One addition from operating this: make the tier-to-model mapping cheap to audit with a per-tier usage counter. Our routing logs the task class and chosen model, and that's how we discovered "quick" explore-type dispatches were quietly the majority of our cost on the wrong tier. Without per-tier token accounting, the mapping is a config guess; with it, the mapping becomes a measurable policy — and it composes naturally with the cost-tracking work in #12377 (a tier field on CostEvents would answer "is quick actually cheap?" directly from session stats).
The layered resolution (agent override → global → parent fallback) also matches how our own configs evolved, so I don't think you'll regret that shape.
chenhz01 commentedon Sep 17, 2026
We run a tiered model-routing setup in production and Solution C is the right shape — raw model IDs in the tool schema age badly for exactly the reasons listed (training cutoff, model proliferation, no validation), while a 3-enum tier keeps the decision space auditable.
One addition from operating this: make the tier-to-model mapping cheap to audit with a per-tier usage counter. Our routing logs the task class and chosen model, and that's how we discovered "quick" explore-type dispatches were quietly the majority of our cost on the wrong tier. Without per-tier token accounting, the mapping is a config guess; with it, the mapping becomes a measurable policy — and it composes naturally with the cost-tracking work in #12377 (a tier field on CostEvents would answer "is quick actually cheap?" directly from session stats).
The layered resolution (agent override → global → parent fallback) also matches how our own configs evolved, so I don't think you'll regret that shape.
RajatGarga commentedon Sep 17, 2026
That might work for workflows that are already well defined, but I do not see how it introduces issues like training cutoff etc. I often tell the session which model to use for what task in a session and the tool call can fail if model id is not correct. The cheapest models of 2026 can handle this failure mode.
I feel adding tiers instead of raw models to subagent tool is akin to replacing one incomplete feature with another. If you want tiered models create a model selection skill where you define the tiers and your agents will use it.
feat(opencode): add per-call subagent model selection to the Task tool
neriousy commentedon Oct 1, 2026
The subagent tool in OpenCode v2 takes an optional
model(providerID/modelID, optionally with#variant), checked against the models you have available. The order of precedence is: a model passed to the tool, then the agent's configured model, then the parent session's model.Added in #49194, which also gives the agent a tool for listing models.
Closing as completed. If something doesn't work on v2, please open a new issue.