Skip to content

BYOK: built-in agents (explore, task, research) never use their default models and silently run on the session model #5126

Open

Description

@SivaKesava1

Describe the bug

Copilot CLI's built-in agents declare their own models in their definitions (unchanged from 1.0.90
to 1.0.96):

Agent Default models, in order Effort
explore gpt-5.6-luna, gpt-5.4-mini low
task gpt-5.6-luna, gpt-5.4-mini, claude-haiku-4.5 -
research claude-sonnet-5 -

In a normal signed-in session these models are used, so a quick explore search runs on a small
model. In a BYOK session they are never used. Every built-in agent runs on the session's
model, even when the BYOK provider serves the default model and the session lists it.

As far as we can tell, the cause is the check that a definition's model is "available" in the
session. Under BYOK it never passes:

The fallback is silent and misreported. It isn't logged at the default log level, and the
subagent.started and subagent.completed events report
"modelSelectionSource": "agent_definition_default" with model set to the session model. That
reads as if the definition chose that model.

Why it matters. A BYOK session on an expensive model makes every built-in agent expensive too.
GitHub Agentic Workflows (github/gh-aw) runs Copilot through a proxy configured as a BYOK provider
and picks the session model per task. On runs on Claude Opus, explore and research used 49–58%
of the run's AI credits, all on Opus, although their definitions ask for Luna, mini and Sonnet.
explore is also slower on a large model.

The provider does serve the default model. As a diagnostic, setting
subagents.agents.explore.model in ~/.copilot/settings.json makes explore run on Luna through
the same provider (modelSelectionSource: "configured_preference"). We don't want to rely on that
setting as a fix: it skips the cost guard (a Sol preference in a Luna session ran on Sol), so every
integrator would have to re-implement the runtime's model choice and cost rule.

Affected version

GitHub Copilot CLI 1.0.96, and @github/copilot-sdk 1.0.19 against copilot --headless 1.0.96. Also seen on 1.0.90 and 1.0.95.

Steps to reproduce the behavior

CLI mode (BYOK straight to the Copilot API, no proxy):

mkdir demo && cd demo
printf 'def add_numbers(a, b):\n    return a + b\n' > math_utils.py
export COPILOT_OFFLINE=true \
  COPILOT_PROVIDER_BASE_URL=https://api.githubcopilot.com \
  COPILOT_PROVIDER_TYPE=openai \
  COPILOT_PROVIDER_WIRE_API=responses \
  COPILOT_PROVIDER_BEARER_TOKEN="$(gh auth token)" \
  COPILOT_MODEL=gpt-5.6-sol
copilot --allow-all-tools --no-ask-user --log-level all --log-dir ./logs -p \
  'Use the task tool with agent_type "explore" to find which file defines add_numbers. Do not search yourself.'

Observed: the output shows ● Explore (model: gpt-5.6-sol), and the log's subagent.started
event has "model":"gpt-5.6-sol","taskModelSource":"unset","modelSelectionSource":"agent_definition_default".

SDK mode: start copilot --headless --port <port> and create a session with these options:

{
  "model": "copilot/gpt-5.6-sol",
  "providers": [{ "name": "copilot", "type": "openai", "wireApi": "responses",
                  "baseUrl": "https://api.githubcopilot.com", "bearerToken": "<token>",
                  "headers": { "Copilot-Integration-Id": "copilot-developer-cli" } }],
  "models": [{ "id": "gpt-5.6-sol", "provider": "copilot" },
             { "id": "gpt-5.6-luna", "provider": "copilot" },
             { "id": "gpt-5.4-mini", "provider": "copilot" }]
}

Send the same prompt.

Observed: subagent.started has "model":"copilot/gpt-5.6-sol","modelSelectionSource":"agent_definition_default",
and every request goes to gpt-5.6-sol. This happens although copilot/gpt-5.6-luna is one of the
session's models.

Control (shows the provider serves Luna): add
{"subagents":{"agents":{"explore":{"model":"gpt-5.6-luna"}}}} to ~/.copilot/settings.json and
rerun the CLI steps. ● Explore (model: gpt-5.6-luna), with
"modelSelectionSource":"configured_preference".

Expected behavior

  1. Under BYOK, a built-in agent uses its definition's model when the session can serve it, just as
    in a signed-in session:
    • SDK mode: match the definition's short name to the session's provider-qualified model
      (gpt-5.6-luna → copilot/gpt-5.6-luna).
    • CLI mode: don't treat COPILOT_MODEL as the only available model. The session needs a way
      to know the provider's other models; Feature request: opt-in model discovery for BYOK / custom providers #3795 (BYOK model discovery) would provide one.
  2. The existing cost guard keeps applying, so a default that costs more than the session model
    (research → Sonnet under Luna) is still skipped. It should also work under BYOK, where pricing
    may have to come from the model id.
  3. A default the session can't reach is skipped, not tried and failed. For example, in CLI mode a
    Claude default under a GPT session model is on the other wire API (BYOK: sub-agents always use the session's wire API, so a sub-agent on a model from the other family fails with a 400 #5103).
  4. When the agent does fall back to the session model, the fallback is visible: logged at info or
    warning level, and reported in subagent.started with its own modelSelectionSource value or a
    fallback reason, not as agent_definition_default.

Additional context

Activity

  1. added theissue type on Oct 12, 2026
  2. SivaKesava1 commented on Oct 13, 2026

    @SivaKesava1
    Author

    More detail on the SDK case, from Copilot CLI 1.0.96 and @github/copilot-sdk 1.0.19:

    The runtime does check the definition's models, and the short name is what fails. The native runtime (prebuilds/<platform>/runtime.node) has this fallback message:

    Agent "<agent>": no model candidates from [...] are available or pass cost guard; falling back to session model "<model>"
    

    So explore's gpt-5.6-luna and gpt-5.4-mini are each checked, and none is accepted.

    The SDK types document that a BYOK model's session-wide selection id is provider-qualified (ProviderModelConfig.id is provider-local, and the session id is provider/id). The same session also rejects a custom agent's short name, with Model 'gpt-5.4-mini' is not available. Available models: copilot/gpt-5.4-mini, …. So the definition's short name never matches copilot/gpt-5.6-luna, although that exact model is in the session (#5127 is the same name matching for custom agents and the session model).

    The fallback message isn't logged. It doesn't appear in the process log or the session events even with --log-level all, and subagent.started reports modelSelectionSource: "agent_definition_default" with the session model.

    What would fix it for SDK BYOK sessions:

    1. When checking a built-in agent's definition models, treat a short name as available if a session model has that id or modelId, and select that model's provider-qualified id. If several providers serve it, prefer the one whose wire API the model supports.
    2. Keep the cost guard for those matches, pricing BYOK models through modelId. If a model can't be priced, log that instead of silently skipping it.
    3. Log the fallback message at info level, and report the fallback in subagent.started (its own modelSelectionSource or a reason).
  3. added
    area:agentsSub-agents, fleet, autopilot, plan mode, background agents, and custom agents
    area:modelsModel selection, availability, switching, rate limits, and model-specific behavior
    and removed on Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:agentsSub-agents, fleet, autopilot, plan mode, background agents, and custom agentsarea:modelsModel selection, availability, switching, rate limits, and model-specific behavior

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions