Skip to content

Subagent models are ignored when using GitHub Copilot provider — All Premium Requests billed to orchestrator model (Claude Opus 4.6) #20859

Closed as not planned

Description

@berrujaime

Description

Summary

When using the GitHub Copilot provider, models configured for subagents (mode: "subagent") are not being respected. Even though OpenCode internally shows usage of the correct models for subagents, all Premium Requests in GitHub Copilot billing are attributed exclusively to the primary/orchestrator model (Claude Opus 4.6).

GitHub Copilot Billing Summary (March 2026)

Total Premium Requests: 300
Claude Opus 4.6: 228 (Mar 26) + 72 (Mar 27) = 300 requests
Claude Sonnet 4.6: 0 requests
GPT-5.4: 0 requests
Gemini 3.1 Pro: 0 requests

All 300 Premium Requests were billed exclusively to Claude Opus 4.6, despite explicitly configuring multiple subagents with cheaper models (Sonnet, Gemini, GPT-5.4).
Notable observation:
In the CSV export from GitHub, models that were supposedly used (Claude Sonnet 4.6, GPT-5.4, Gemini 3.1 Pro) appear in the report but with 0 requests. Other models that were never used during the period do not appear at all. This suggests that GitHub is aware of the configured models, but is still routing and billing all activity through the orchestrator’s model (Opus).

→ Total: 300 Premium Requests, all charged to Claude Opus 4.6. Other models show 0.

Evidence from OpenCode

Output from opencode stats --models (github-copilot models only):

github-copilot/claude-sonnet-4.6
  Messages: 845
  Input Tokens: 2.7M
  Output Tokens: 487.4K

github-copilot/claude-opus-4.6
  Messages: 491
  Input Tokens: 4.3M
  Output Tokens: 301.6K

github-copilot/gemini-3.1-pro-preview
  Messages: 33
  ...

github-copilot/gpt-5.4
  Messages: 19
  ...

Configuration (opencode.json)

Relevant agents configuration:

  • "gentleman" → mode: "primary", model: "github-copilot/claude-opus-4.6"
  • "sdd-orchestrator" → mode: "primary", model: "github-copilot/claude-opus-4.6"
  • "sdd-apply" → mode: "subagent", model: "github-copilot/claude-sonnet-4.6"
  • "sdd-archive" → mode: "subagent", model: "github-copilot/claude-sonnet-4.6"
  • "sdd-design" → mode: "subagent", model: "github-copilot/claude-opus-4.6"
  • "sdd-explore" → mode: "subagent", model: "github-copilot/claude-sonnet-4.6"
  • "sdd-init" → mode: "subagent", model: "github-copilot/claude-sonnet-4.6"
  • "sdd-propose" → mode: "subagent", model: "github-copilot/gemini-3.1-pro-preview"
  • "sdd-spec" → mode: "subagent", model: "github-copilot/gemini-3.1-pro-preview"
  • "sdd-tasks" → mode: "subagent", model: "github-copilot/gpt-5.4"
  • "sdd-verify" → mode: "subagent", model: "github-copilot/gpt-5.4"

Additional observation

When I inspected subagents inside OpenCode, it appeared that the correct model was being selected for each subagent. However, in the final GitHub Copilot billing, everything was still charged under the orchestrator model (Claude Opus 4.6).

Expected behavior

Subagents should execute using their explicitly configured model, and Premium Requests should be billed according to the actual model used in each call (or at least not force everything to the primary agent’s model).

This issue causes significant over-consumption of the most expensive model (Opus) even when cheaper models are explicitly assigned to subagents.

OpenCode version: 1.3.13

Plugins

opencode-copilot-auth (the official bridge between OpenCode and GitHub Copilot)

OpenCode version

1.3.13

Steps to reproduce

  1. Configure multiple subagents with different github-copilot/* models.
  2. Run complex workflows using the orchestrator that heavily delegate to subagents.
  3. Compare opencode stats --models with the downloaded GitHub Copilot usage CSV.

Screenshot and/or share link

No response

Operating System

Ubuntu 24.04.1

Terminal

wsl in windows terminal

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Apr 3, 2026
  2. github-actions commented on Apr 3, 2026

    @github-actions
    Contributor

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

    If your issue is distinct from the above (e.g., the billing attribution specifically rather than model selection), please clarify the difference.

  3. berrujaime commented on Apr 3, 2026

    @berrujaime
    Author

    This issue is not a duplicate of the two mentioned.

    #18615 is about the model parameter being ignored when launching a subagent by agent name (it falls back to the agent's built-in chain). In my case, the subagents are correctly using the models I configured. I can confirm this with opencode stats --models, where I see messages and tokens being consumed on Claude Sonnet 4.6, GPT-5.4, Gemini 3.1 Pro, etc.
    #16937 is about the Desktop App consuming separate premium requests per subagent (higher total usage). My issue is different: it's about billing attribution.

    Actual problem:
    Even though OpenCode internally executes the subagents with their configured cheaper models, all Premium Requests (300 in my case) are being billed by GitHub Copilot exclusively to the orchestrator's model (Claude Opus 4.6). In the GitHub Copilot usage CSV, the other models show 0 requests.

    In short:

    Model selection works correctly at runtime.
    Billing attribution fails with the GitHub Copilot provider: everything is charged to the expensive main agent model.

    Can this be reviewed by the team? It appears there is an issue with how the model is passed to the GitHub Copilot API when using subagents in "subagent" mode.

  4. gndk commented on Apr 4, 2026

    @gndk

    Subagents should not consume any additional requests at all since they are not user requests. Which is also the behaviour I see when using the same model for subagents. Maybe your mismatch actually is caused by the model switch in subagent config?

  5. berrujaime commented on Apr 4, 2026

    @berrujaime
    Author

    Subagents should not consume any additional requests at all since they are not user requests. Which is also the behaviour I see when using the same model for subagents. Maybe your mismatch actually is caused by the model switch in subagent config?

    No, it's not caused by a model switch.
    When I configure subagents with different/cheaper models (Claude Sonnet 4.6, GPT-5.4, Gemini, etc.), they internally use those models correctly. I can clearly see this in opencode stats --models, with thousands of input/output tokens consumed on the cheaper models.
    However, in the GitHub Copilot usage CSV, all premium requests (hundreds) are still attributed only to the orchestrator model (github-copilot/claude-opus-4.6). The other models show 0 requests.
    When all subagents use the same model as the orchestrator, billing works fine (only 1 premium request). The problem only appears when using different models in subagents.
    This looks like a billing attribution issue with the GitHub Copilot provider when model switching is used in subagent mode.

  6. kendotpm commented on Apr 13, 2026

    @kendotpm

    However, in the GitHub Copilot usage CSV, all premium requests (hundreds) are still attributed only to the orchestrator model (github-copilot/claude-opus-4.6). The other models show 0 requests.

    That's exactly how github copilot bills.

    If you try the reverse (free orchestrating to premium), you won't see any premium usage increases. For how long I don't know, its been patched out of VS and CLI when you go this reverse direction.

    If you were to parallelize your sub-agents as full-blown agents and have your orchestrator shipping messages to them as new sessions (not via the task tool, just straight up non-interactive bash calls), you'd see all that usage pile up in Github billing.

    @gndk's first sentence is accurate. Emphasis mine:

    Subagents should not consume any additional requests at all since they are not user requests.


    Orchestrators don't save you requests, they save you context so your smart orchestrator can keep everything together while your cheaper coders / reviewers don't clog up the orchestrator's context (particularly important on copilot's miniscule context sizes).

    Here's Opus explaining how the copilot plugin is instrumented in opencode.


    Two-Layer System

    The plugin lives at packages/opencode/src/plugin/copilot.ts in the OpenCode monorepo.

    Layer 1 — Fetch wrapper (runs on every API call)

    Parses the request body to determine x-initiator:

    • OpenAI format: isAgent = last.role !== "user" — if the last message is a tool result (role "tool") or assistant, it's agent-initiated
    • Anthropic format: isAgent = !(last.role === "user" && hasNonToolCalls) — special handling for mixed content (tool_result + text in same message)
    • Parse failure: defaults to "user" (conservative — may overcount)

    Layer 2 — chat.headers plugin hook (runs before fetch, can override)

    Three cases:

    1. Compaction request → forces x-initiator: "agent" (free)
    2. Sub-session (has parentID) → forces x-initiator: "agent" (free)
    3. Neither → does NOT set header (defers to Layer 1)
      Plugin output spreads AFTER fetch-level, so the plugin hook wins when it sets a value.

    The Agent → Subagent Chain for 0x orchestrator → 3x subagent.

    User prompt
      → Orchestrator session (parentID = NULL)
          → Fetch wrapper: last.role = "user" → x-initiator: "user"
          → Plugin hook: no parentID → no override
          → RESULT: BILLED at model multiplier (0× for GPT-4.1)
    
      → Orchestrator calls Task tool → spawns subagent session (parentID = orchestrator's sessionID)
          → Every API call in subagent:
              → Fetch wrapper: would set "user" or "agent" based on message roles
              → Plugin hook: parentID IS SET → forces "agent" (overrides fetch wrapper)
              → RESULT: FREE — always, regardless of model or message role
    

    The parentID check is the mechanism that makes subagent calls unconditionally free. It doesn't matter what model the subagent uses or what the message roles look like — if parentID is set, the plugin forces "agent" and billing never sees it.

    Edit: formatting

  7. removed
    bugSomething isn't working
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  8. gauravlochan commented on Jun 2, 2026

    @gauravlochan

    That's exactly how github copilot bills.

    The parentID check is the mechanism that makes subagent calls unconditionally free. It doesn't matter what model the subagent uses or what the message roles look like — if parentID is set, the plugin forces "agent" and billing never sees it.

    @kendotpm That is so strange. So the fix would have to come from GitHub?

  9. github-actions commented on Aug 2, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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