diff --git a/packages/server/src/server/agent/providers/codex-app-server-agent.features.test.ts b/packages/server/src/server/agent/providers/codex-app-server-agent.features.test.ts index ff0dab49a6..9cbc0ccf0e 100644 --- a/packages/server/src/server/agent/providers/codex-app-server-agent.features.test.ts +++ b/packages/server/src/server/agent/providers/codex-app-server-agent.features.test.ts @@ -326,6 +326,44 @@ describe("Codex app-server provider controls", () => { } }); + test("a Fast chosen by alias is kept as the catalog's id, so a model with a different Fast id resets it", async () => { + const { session, appServer } = await createConnectedSession( + { model: "model-a" }, + { + models: [ + { + id: "model-a", + isDefault: true, + serviceTiers: [{ id: "priority", name: "Fast", description: "Faster" }], + }, + { + id: "model-b", + serviceTiers: [{ id: "rapid", name: "Fast", description: "Faster" }], + }, + ], + }, + ); + const events: AgentStreamEvent[] = []; + session.subscribe((event) => events.push(event)); + try { + await expect(session.applyOptions?.({ fast_mode: true })).resolves.toEqual({ + service_tier: "priority", + fast_mode: null, + }); + + await session.setModel("model-b"); + + // The option the session reports and the tier the turn runs are the same speed. + expect(events.filter((event) => event.type === "options_changed")).toEqual([ + expect.objectContaining({ patch: { service_tier: "default" } }), + ]); + await session.startTurn("hello"); + await expect(appServer.waitForTurnStart()).resolves.toMatchObject({ serviceTier: "default" }); + } finally { + await session.close(); + } + }); + test("maps legacy Fast commands to the catalog's request id", async () => { const { session, appServer } = await createConnectedSession(); try { diff --git a/packages/server/src/server/agent/providers/codex-app-server-agent.ts b/packages/server/src/server/agent/providers/codex-app-server-agent.ts index 82dab386cc..c928b27e58 100644 --- a/packages/server/src/server/agent/providers/codex-app-server-agent.ts +++ b/packages/server/src/server/agent/providers/codex-app-server-agent.ts @@ -4729,8 +4729,11 @@ export class CodexAppServerAgentSession implements AgentSession { ); } } - this.providerOptions = { ...valid, ...(requestedTier ? { service_tier: requestedTier } : {}) }; - this.requestedServiceTier = requestedTier; + // The session keeps the catalog's id for the tier, so a later model switch sees what runs. + const accepted = requestedTier && (this.resolveServiceTier(requestedTier) ?? requestedTier); + const { fast_mode: _folded, ...kept } = valid; + this.providerOptions = { ...kept, ...(accepted ? { service_tier: accepted } : {}) }; + this.requestedServiceTier = accepted || null; if ("plan_mode" in options) this.setPlanMode(options.plan_mode === true); this.cachedRuntimeInfo = null; // COMPAT(codexFastPreference): added in v0.10.0, remove after 2027-03-29 once clients use service_tier.