fix(server): keep a provider-side model switch across reload

A model_changed event from the provider updated runtimeInfo.model but
left config.model at the creation-time value. Reload and daemon restart
resume from config.model, so the resumed session was switched back to
the old model. model_changed now writes config.model, as
thinking_option_changed already does for config.thinkingOptionId.

Co-authored-by: Edo Sulaiman <edosulai@icloud.com>
This commit is contained in:
paseo-bot[bot]
2026-09-28 23:02:03 +02:00
co-authored by Edo Sulaiman
parent f4ba16a0b3
commit 37fd9259e0
2 changed files with 37 additions and 0 deletions
@@ -5066,6 +5066,42 @@ test("session config drift events update state through the stream channel", asyn
expect(streams.map((event) => event.type)).toEqual([]);
});
test("provider-side model switch survives reload and daemon restart", async () => {
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-provider-model-switch-"));
const storage = new AgentStorage(join(workdir, "agents"), logger);
let capturedSession: TestAgentSession | null = null;
class ModelSwitchClient extends TestAgentClient {
override async createSession(config: AgentSessionConfig): Promise<AgentSession> {
capturedSession = new TestAgentSession(config);
return capturedSession;
}
}
const client = new ModelSwitchClient();
const manager = new AgentManager({
clients: { codex: client },
registry: storage,
logger,
idFactory: () => "00000000-0000-4000-8000-000000000134",
});
const snapshot = await manager.createAgent(
{ provider: "codex", cwd: workdir, model: "gpt-5.2-codex" },
undefined,
{ workspaceId: undefined },
);
capturedSession!.pushEvent({
type: "model_changed",
provider: "codex",
runtimeInfo: { provider: "codex", sessionId: capturedSession!.id, model: "gpt-5.4" },
});
await manager.flush();
await manager.reloadAgentSession(snapshot.id);
expect(client.resumeOverrides.at(-1)?.model).toBe("gpt-5.4");
expect((await storage.get(snapshot.id))?.config?.model).toBe("gpt-5.4");
rmSync(workdir, { recursive: true, force: true });
});
test("setLabels merges and persists labels", async () => {
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-set-labels-"));
const storagePath = join(workdir, "agents");
@@ -4310,6 +4310,7 @@ export class AgentManager {
return undefined;
case "model_changed":
agent.runtimeInfo = event.runtimeInfo;
agent.config.model = event.runtimeInfo.model ?? agent.config.model;
if (!agent.persistence && event.runtimeInfo.sessionId) {
agent.persistence = attachPersistenceCwd(
{ provider: agent.provider, sessionId: event.runtimeInfo.sessionId },