Skip to content

spawn_agent(model="gpt-5.4-mini") produces child thread metadata with model="gpt-5.4" #15177

Closed as duplicate

Description

@himwichboys

What version of the Codex App are you using (From “About Codex” dialog)?

26.317.21539 (1088)

What subscription do you have?

Pro

What platform is your computer?

Darwin 25.3.0 arm64 arm

What issue are you seeing?

## Summary

Codex subagents spawned with `model: "gpt-5.4-mini"` are later recorded in the child thread metadata as `model: "gpt-5.4"`.

This makes the child thread UI show `GPT-5.4`, even though the parent explicitly requested `gpt-5.4-mini`.

## Environment

- Product: Codex desktop app
- Version: `0.116.0-alpha.1`
- Date observed: `2026-03-19`
- Timezone: `America/New_York`

## Expected behavior

When the parent thread calls `spawn_agent` with:

```json
{
  "model": "gpt-5.4-mini",
  "reasoning_effort": "xhigh"
}

the spawned child thread should preserve and display that same model in its persisted metadata and UI.

Actual behavior

The parent thread log shows the subagent was spawned with model: "gpt-5.4-mini", but the child thread’s persisted turn_context records model: "gpt-5.4".

What steps can reproduce the bug?

Minimal repro

  1. In Codex desktop, ask the parent agent to spawn a subagent with:
    • model: "gpt-5.4-mini"
    • reasoning_effort: "xhigh"
  2. Open the spawned child thread
  3. Check the child thread’s displayed model and persisted session metadata
  4. Observe that the child thread is recorded as gpt-5.4

Evidence

Parent thread spawn_agent call:

{
  "agent_type": "explorer",
  "fork_context": true,
  "model": "gpt-5.4-mini",
  "reasoning_effort": "xhigh",
  "message": "Perform a bug-focused review..."
}

Child thread persisted context:

{
  "type": "turn_context",
  "payload": {
    "model": "gpt-5.4",
    "collaboration_mode": {
      "mode": "plan",
      "settings": {
        "model": "gpt-5.4",
        "reasoning_effort": "xhigh"
      }
    }
  }
}

Notes

This proves that:

  • the parent requested gpt-5.4-mini
  • the child thread metadata was recorded as gpt-5.4

It does not prove from logs alone whether inference actually ran on mini or was remapped before execution.

So the issue appears to be in one of:

  • spawn_agent model handling
  • child-thread metadata persistence
  • UI provenance/display of spawned model

Impact

This makes it hard to trust or verify delegated model selection for:

  • cost-sensitive fan-out reviews
  • performance comparisons
  • debugging subagent behavior differences

Suggested investigation

Please check whether:

  • spawn_agent.model is being dropped or normalized during child-thread creation
  • child turn_context.model is defaulting to the parent model
  • the UI is reading thread-default model instead of actual spawned-run model provenance

```md
### Sanitized log excerpts

Parent session:
```json
{"type":"response_item","payload":{"type":"function_call","name":"spawn_agent","arguments":"{\"agent_type\":\"explorer\",\"fork_context\":true,\"model\":\"gpt-5.4-mini\",\"reasoning_effort\":\"xhigh\",\"message\":\"Perform a bug-focused review...\"}"}}

Child session:

{"type":"turn_context","payload":{"model":"gpt-5.4","collaboration_mode":{"mode":"plan","settings":{"model":"gpt-5.4","reasoning_effort":"xhigh"}}}}

### What is the expected behavior?

_No response_

### Additional information

When a parent thread spawns a subagent with an explicit model override like `model: "gpt-5.4-mini"` and `reasoning_effort: "xhigh"`, the spawned child thread should preserve that exact model in its persisted metadata and display it consistently in the UI.

Concretely, I expect:
- the child thread metadata to record `gpt-5.4-mini`
- the child thread UI/model picker to show `GPT-5.4-mini`
- no silent normalization or fallback to `gpt-5.4` unless Codex explicitly reports that fallback to the user

Activity

  1. added
    appIssues related to the Codex desktop app
    on Mar 19, 2026
  2. jhste102lab commented on Mar 27, 2026

    @jhste102lab

    I can still reproduce this on current main (be5afc65d31728c11d67c589cebbc64a87979e74) in the CLI, not just in Desktop/VS Code.

    What I verified on March 27, 2026:

    • Built Codex locally from source at be5afc6
    • Ran a minimal codex exec repro that spawns exactly one explorer
    • Parent spawn_agent call explicitly requested:
      • agent_type: "explorer"
      • model: "gpt-5.4-mini"
      • reasoning_effort: "xhigh"
    • Spawned child session was created successfully and completed its task

    But the persisted child session metadata still records the inherited/default model instead of the requested explorer override:

    • Parent session: 019d2d8c-eef0-7f03-baa3-6aa4605e3afe
    • Child session: 019d2d8d-2697-76d0-99fa-ac765ee8db15

    Observed in the logs:

    Parent session:

    {"type":"function_call","name":"spawn_agent","arguments":"{\"agent_type\":\"explorer\",\"fork_context\":false,\"model\":\"gpt-5.4-mini\",\"reasoning_effort\":
    \"xhigh\",...}"}
    
    Child session turn_context:
    
    {
      "model": "gpt-5.4",
      "collaboration_mode": {
        "mode": "default",
        "settings": {
          "model": "gpt-5.4",
          "reasoning_effort": "medium"
        }
      },
      "effort": "medium"
    }
    
    So at minimum, this is still a child-session metadata / provenance bug on current main.
    
    I still cannot prove from logs alone whether actual inference ran on gpt-5.4-mini and only the metadata is wrong, or whether the override is being lost before
    execution. But the persisted child metadata is definitely inconsistent with the parent spawn_agent request.
    
    This seems broader than the original desktop-only framing, since I reproduced it in codex exec on a source build from current main.
    
    If useful, I can provide a more compact minimal repro prompt/command shape as well.
  3. ozan-s commented on Apr 4, 2026

    @ozan-s

    I'm also seeing sub-agents ignore the model I request. When I spawn with model: "gpt-5.4-mini", the agent runs on the parent's model ("gpt-5.4") instead.

    This only happens with the "explorer" agent type. The "explorer" role has an associated config file (explorer.toml) that triggers a full config rebuild during spawn. That rebuild preserves model_provider but not model, so the requested model is lost and falls back to the parent session's model. The "default" role has no config file, so it skips the rebuild entirely and respects the model you specify.

    Workaround: Use "default" as the agent type instead of "explorer". The model selection will then work as expected.

    Here is the proof:

    › Launch three agents, one for each type with a dummy request (read only). Launch them all with gpt-5.4-mini high reasoning.
    
    • Using the requested setup now: I’ll spawn three subagents in parallel (default, explorer, worker), each with a read-only dummy task, all on gpt-5.4-mini with high reasoning.
    
    • Spawned Bohr [default] (gpt-5.4-mini high)
      └ Dummy read-only task: inspect repository root and report the first 10 top-level entries. Do not modify any files or run destructive commands.
    
    • Spawned Tesla [explorer] (gpt-5.3-codex medium)
      └ Dummy read-only task: find AGENTS.md files in this workspace and return their paths only. Read-only; do not modify files.
    
    • Spawned Pasteur [worker] (gpt-5.4-mini high)
      └ Dummy read-only task: run a safe read-only check (`git status --short`) and report output summary. Do not edit files, stage changes, or run destructive comma...
    
  4. ozan-s commented on Apr 4, 2026

    @ozan-s

    And here is the proposed fix:

    ⏺ Root Cause Identified
    
      The bug is an ordering issue in the spawn handler. Both V1 and V2 have the same problem.
    
      The exact flow (both multi_agents/spawn.rs and multi_agents_v2/spawn.rs):
    
      1. build_agent_spawn_config — creates config with config.model = parent_model (e.g., "gpt-5.4") — multi_agents_common.rs:226
      2. apply_requested_spawn_agent_model_overrides — sets config.model = "gpt-5.4-mini" (what you requested) — multi_agents_common.rs:298
      3. apply_role_to_config — rebuilds the entire Config from scratch using the config layer stack — role.rs:69
    
      Why the model gets lost:
    
      apply_role_to_config calls build_next_config which rebuilds the config from layers. Inside reload::reload_overrides (role.rs:253-262), the function preserves cwd and model_provider, but does NOT preserve model:
    
      fn reload_overrides(config: &Config, preserve_current_provider: bool) -> ConfigOverrides {
          ConfigOverrides {
              cwd: Some(config.cwd.to_path_buf()),
              model_provider: preserve_current_provider.then(|| config.model_provider_id.clone()),
              // model is NOT preserved! Falls back to Default::default() → None
              ..Default::default()
          }
      }
    
      Then in Config::load_config_with_layer_stack (mod.rs:2440):
      let model = model.or(config_profile.model).or(cfg.model);
      //          ^^^^ None (from overrides) → falls through to profile/global config model → "gpt-5.4"
    
      So the requested "gpt-5.4-mini" set in step 2 is wiped out by the config rebuild in step 3, and the agent inherits the parent's model from the config layers.
    
      Why it only affects certain agent types:
    
      The "default" role has config_file: None, so apply_role_to_config_inner returns early without rebuilding. But "explorer" has config_file: Some("explorer.toml") — even though the file is empty, the rebuild still
      runs and wipes the model override.
    
      Fix
    
      The fix is to swap the order: apply the model override AFTER the role config rebuild.
    
      In both multi_agents/spawn.rs and multi_agents_v2/spawn.rs, change from:
    
      apply_requested_spawn_agent_model_overrides(...)?;  // Sets requested model
      apply_role_to_config(&mut config, role_name)?;       // Rebuilds config, LOSES the model
    
      To:
    
      apply_role_to_config(&mut config, role_name)?;       // Rebuilds config first
      apply_requested_spawn_agent_model_overrides(...)?;    // THEN set requested model
    
  5. added
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    on Apr 25, 2026
  6. Keesan12 commented on May 18, 2026

    @Keesan12

    Even if inference is actually running on mini, the metadata mismatch is still a real bug because cost and behavior analysis depend on the persisted receipt, not just the hidden execution path. I would treat this as provenance, not cosmetics: requested model, resolved model, displayed model, and actual execution model should either match or be shown explicitly when they do not. We ended up needing that exact split in MartinLoop once fan-out comparisons got more cost-sensitive.

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

    appIssues related to the Codex desktop appbugSomething isn't workingsessionIssues involving session (thread) management, resuming, forking, naming, archiving

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions