Skip to content

[FEATURE]: Dynamic model selection for subagents via Task tool #6651

Closed

Description

@mcking-07

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-advanced all 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

  • explore with model_tier="quick" -> no agent override -> uses global tier -> Haiku
  • code-review with model_tier="quick" -> uses agent model_tiers -> Sonnet (override)
  • code-review with model_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 tier
  • max_tokens - limit output tokens for cost control
  • top_p - adjust sampling for tier
  • timeout - 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

  1. added
    discussionUsed for feature requests, proposals, ideas, etc. Open discussion
    on Jan 2, 2026
  2. github-actions commented on Jan 2, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if these don't address your specific case.

  3. changed the title [-][FEATURE] Dynamic model selection for subagents via Task tool[/-] [+][FEATURE]: Dynamic model selection for subagents via Task tool[/+] on Jan 3, 2026
  4. m10rten commented on Jan 7, 2026

    @m10rten

    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.

  5. mcking-07 commented on Jan 8, 2026

    @mcking-07
    Author

    @m10rten Could you clarify what you mean by

    a primary agent calling subagents controls this

    The feature I'm proposing DOES let the primary agent control the model via the model_tier parameter 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.)"

  6. m10rten commented on Jan 8, 2026

    @m10rten

    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.)"

    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...

  7. mcking-07 commented on Jan 15, 2026

    @mcking-07
    Author

    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 variant as 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.json can also include variants:

    {
      "agent": {
        "explore": {
          "model_tiers": {
            "quick": { "model": "openai/gpt-5.2", "variant": "high" }
          },
          "variant": "medium"
        }
      }
    }

    Priority Order

    Model Resolution:

    1. agent.model - explicit agent config
    2. agent.model_tiers[tier]?.model - per-agent tier override
    3. config.model_tiers[tier]?.model - global tier config
    4. Parent session model - fallback

    Variant Resolution:

    1. agent.variant - explicit agent config
    2. agent.model_tiers[tier]?.variant - per-agent tier variant

    Summary

    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.

  8. dpearson2699 commented on Jan 21, 2026

    @dpearson2699

    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.json with model_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, task invocations 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:

    • the subagent’s statically configured agent.model, otherwise
    • inherits the caller’s session/message model.

    That 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. model as a string like anthropic/... or an enum model_tier), so orchestrator-style workflows (like gsd-opencode) can select different models per subagent without duplicating agents.

    Suggested resolution order:

    1. If Task call specifies model/model_tier, use it.
    2. Else if agent has agent.model, use it.
    3. Else inherit parent session model.

    This preserves current behavior by default.

  9. enesgur commented on Jan 21, 2026

    @enesgur

    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.

  10. mcking-07 commented on Jan 30, 2026

    @mcking-07
    Author

    update

    Implemented in PR #11377

    This follows the unified approach (Solution C) from the issue - added model_tier parameter to Task tool with quick/standard/advanced tiers. 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 variant for models that support it.

    Note on related PRs:

    • PR #7140 and PR #7156 add static default variant per agent
    • My PR #11377 enables dynamic model selection via tiers at call time

    These are complementary - agents can have default variants while still allowing tier-based overrides via Task tool.

  11. Steffen025 commented on Feb 3, 2026

    @Steffen025

    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 model field.

    Why Tiers Won't Fully Solve This

    The model_tier approach (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 model field when no tier is specified?

    Summary

  12. mcking-07 commented on Feb 4, 2026

    @mcking-07
    Author

    @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:

    Or alternatively, respect the agent's configured model field when no tier is specified?

    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.

  13. unomaas commented on Feb 10, 2026

    @unomaas

    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!

  14. Steffen025 commented on Feb 10, 2026

    @Steffen025

    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 select quick/standard/advanced based 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.

  15. 22 remaining items

  16. adambak033 commented on May 28, 2026

    @adambak033

    Bump as well, sooooo needed! ✨

  17. trevor-vaughan commented on May 28, 2026

    @trevor-vaughan

    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 say sonnet and 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.

  18. xintron commented on May 28, 2026

    @xintron

    I want to be able to just say sonnet and have it pick the latest model.

    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 sonnet and get the model you have favorited on top. Right now, it's the oldest model due to how the sorting works on plain strings.

  19. mcking-07 commented on May 31, 2026

    @mcking-07
    Author

    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_tier parameter + config resolution). If any of you want to champion the fuzzy matching or model picker sorting, I'd +1 those as follow-ups.

  20. Ylandolsi commented on Jul 10, 2026

    @Ylandolsi

    bump !

  21. connor-kress commented on Jul 11, 2026

    @connor-kress

    #34947 seems to be a more up to date implementation of this.

  22. RajatGarga commented on Aug 22, 2026

    @RajatGarga

    Bump!

  23. balboah commented on Sep 15, 2026

    @balboah

    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".

  24. chenhz01 commented on Sep 17, 2026

    @chenhz01

    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.

  25. chenhz01 commented on Sep 17, 2026

    @chenhz01

    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.

  26. RajatGarga commented on Sep 17, 2026

    @RajatGarga

    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.

    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.

  27. neriousy commented on Oct 1, 2026

    @neriousy
    Member

    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.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions