[AI] fix(sessions): set liveModelSwitchPending when switching to default with runtime-only fields (#96318)

When a session's model comes from steering/fallback runtime fields
(entry.modelProvider/entry.model) rather than explicit override fields,
switching back to the default model via /model default would not set
liveModelSwitchPending. The isDefault branch in applyModelOverrideToSessionEntry
only sets selectionUpdated when it deletes override fields — but when no
override fields exist, selectionUpdated stays false, preventing the
liveModelSwitchPending flag from being set at the gate condition.

Fix: after the runtime alignment check, set selectionUpdated when
selection.isDefault and runtime fields are misaligned, so that
liveModelSwitchPending is properly set for the pending live switch.

Adds test coverage for this previously untested scenario.

Related to #96269

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
SunnyShu
2026-06-24 19:51:37 +08:00
committed by GitHub
parent 1069c60e1e
commit 2a484a3ff1
2 changed files with 41 additions and 0 deletions

View File

@@ -180,6 +180,39 @@ describe("applyModelOverrideToSessionEntry", () => {
expect((entry.updatedAt ?? 0) > before).toBe(true);
});
it("sets liveModelSwitchPending when switching to default with runtime-only fields", () => {
const entry: SessionEntry = {
sessionId: "sess-96269",
updatedAt: Date.now() - 5_000,
modelProvider: "anthropic",
model: "claude-sonnet-4-6",
contextTokens: 200_000,
contextBudgetStatus: contextBudgetStatus({
updatedAt: Date.now() - 5_000,
provider: "anthropic",
model: "claude-sonnet-4-6",
contextTokenBudget: 200_000,
}),
};
const result = applyModelOverrideToSessionEntry({
entry,
selection: {
provider: "openai",
model: "gpt-5.4",
isDefault: true,
},
markLiveSwitchPending: true,
});
expect(result.updated).toBe(true);
expect(entry.modelProvider).toBeUndefined();
expect(entry.model).toBeUndefined();
expect(entry.contextTokens).toBeUndefined();
expect(entry.contextBudgetStatus).toBeUndefined();
expect(entry.liveModelSwitchPending).toBe(true);
});
it("marks non-default overrides with the provided source", () => {
const entry: SessionEntry = {
sessionId: "sess-5a",

View File

@@ -93,6 +93,14 @@ export function applyModelOverrideToSessionEntry(params: {
}
}
// When switching back to the default model without override fields to delete
// (e.g. model comes from steering/fallback runtime fields), the isDefault
// branch at line 42 won't set selectionUpdated. Mark it here so that
// liveModelSwitchPending can still be set below when runtime is misaligned.
if (selection.isDefault && runtimePresent && !runtimeAligned) {
selectionUpdated = true;
}
// contextTokens are derived from the active session model. When the selected
// model changes (or runtime model is already stale), the cached window can
// pin the session to an older/smaller limit until another run refreshes it.