Skip to content

session/load returns the config.toml model/effort instead of the thread's, because thread/resume is always sent a modelProvider #343

Description

@julianmesa-gitkraken

Setup: codex-acp driven over ACP by Kepler (Electron client, spawns the wrapper via dist/index.js and resumes stored sessions with session/load). Reproduced on codex-acp 1.1.4 and 1.1.7, against codex-cli 0.144.6 app-server.

Problem

session/load returns the model and reasoning effort from ~/.codex/config.toml instead of the ones persisted on the thread. Any in-session model/effort switch is silently lost on resume.

The cause is the modelProvider field that loadSession/resumeSession always pass to thread/resume:

// dist/index.js (1.1.7:26277) — same in 1.1.4:26044
const response = await this.codexClient.threadResume({
  config: await this.createSessionConfig(...),
  cwd: request.cwd,
  modelProvider: await this.getResumeModelProvider(),  // never absent
  threadId: request.sessionId,
});

getResumeModelProvider() is getCurrentModelProvider() ?? "openai", so the field is always populated even with no gateway configured. Passing it makes the app-server discard the thread's stored model/reasoningEffort and re-resolve them from config.

Reproduction

  1. Create a session and switch it to a model/effort that differs from ~/.codex/config.toml. Mine has model = "gpt-5.5", model_reasoning_effort = "xhigh"; the session was set to gpt-5.6-sol / max.
  2. Send a prompt. The rollout jsonl records the switch: "model":"gpt-5.6-sol", "effort":"max" in turn_context.
  3. Resume that thread with session/load.

Observed on both versions:

currentModelId= gpt-5.5[xhigh]
  model            => "gpt-5.5"
  reasoning_effort => "xhigh"

Expected gpt-5.6-sol / max (what the thread holds).

Isolating it to modelProvider

Calling thread/resume directly on the app-server for the same thread, varying only which params are sent:

params sent model reasoningEffort
threadId, cwd gpt-5.6-sol max
+ config gpt-5.6-sol max
+ modelProvider: "openai" gpt-5.5 xhigh
+ config + modelProvider (what codex-acp sends) gpt-5.5 xhigh

config is irrelevant; modelProvider alone flips it. The values it falls back to are exactly the ones in config.toml.

Expected

Resuming a thread should restore the model and reasoning effort stored on that thread. Either don't send modelProvider on thread/resume when no gateway is configured, or have the app-server keep the thread's model when a provider is passed. If the app-server behaviour is the intended contract, this is arguably an openai/codex bug and I'm happy to move it there.

Impact

The client cannot recover the picks on its own: after a client restart there is no live session left to read them from, and the resume response is the only source of truth. Users see the correct model for a moment (from the client's own cache), then it flips to the config default as the load response lands.

Possibly the same root cause as #336, which reports effort reverting between turns of a live session — that one survives without a resume, so it may be a separate path. Filing this separately since the trigger here is isolated to session/load.

Metadata

Metadata

Assignees

No one assigned

    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