fix(ui): stop the echo of a Default send from erasing the recorded Default
The send write was fixed, but the message that send echoes back arrives with model metadata and no effort, and its model matches the one the send just saved. That is exactly when `shouldPreserveManualModelOverride` declines to protect the selection, so the history branch ran with no variant and recorded "no choice" over the user's explicit `Default`. Picking Default, sending, then switching agent and back still put the settings default in the picker. A message carrying no effort is not evidence that the session has none. The history branch now keeps whatever the session already recorded when the message carries no variant, and a concrete historical effort still replaces it. The behavior test ran the real guard through a mock that returned a fixed answer, so the failing branch had no coverage. It now calls the real function unless a test opts out, and the new case fails without this change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZuVVgziiLjD81W5vaxdH2
This commit is contained in:
co-authored by
Claude Opus 5
parent
9299e2a28d
commit
16f6f27027
@@ -878,11 +878,24 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
&& getModelVariantOptions(latestLoadedUserChoice.providerID, latestLoadedUserChoice.modelID).includes(latestLoadedUserChoice.variant)
|
||||
? latestLoadedUserChoice.variant
|
||||
: undefined;
|
||||
const restoreAgentName = latestLoadedUserChoice.agent || currentAgentName || undefined;
|
||||
// A message carrying no effort is not evidence that the user has none:
|
||||
// a send under an explicit "Default" carries none either, and the echo
|
||||
// of that very send arrives here. Keep what the session already
|
||||
// recorded, and let a concrete historical effort replace it.
|
||||
const restoredVariant = historicalVariant ?? (currentSessionId && restoreAgentName
|
||||
? getAgentModelVariantForSession(
|
||||
currentSessionId,
|
||||
restoreAgentName,
|
||||
latestLoadedUserChoice.providerID,
|
||||
latestLoadedUserChoice.modelID,
|
||||
)
|
||||
: undefined);
|
||||
const applyResult = applyModelSelectionWithVariant(
|
||||
latestLoadedUserChoice.providerID,
|
||||
latestLoadedUserChoice.modelID,
|
||||
historicalVariant,
|
||||
latestLoadedUserChoice.agent || currentAgentName || undefined,
|
||||
restoredVariant,
|
||||
restoreAgentName,
|
||||
);
|
||||
if (applyResult !== 'applied') {
|
||||
return;
|
||||
@@ -906,6 +919,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
latestLoadedUserChoice,
|
||||
setAgent,
|
||||
applyModelSelectionWithVariant,
|
||||
getAgentModelVariantForSession,
|
||||
getModelVariantOptions,
|
||||
getSessionModelSelection,
|
||||
resolveModelVariantSelection,
|
||||
|
||||
@@ -40,7 +40,7 @@ const provider = { id: PROVIDER_ID, name: PROVIDER_ID, models: [model] };
|
||||
const agent = { name: AGENT, mode: 'primary' as const };
|
||||
|
||||
let latestUserChoice: UserModelChoice | null = null;
|
||||
let preserveManualOverride = false;
|
||||
let forcePreserveManualOverride: boolean | null = null;
|
||||
|
||||
/** Every effort written for the session, in order, including `undefined`. */
|
||||
const variantWrites: VariantChoice[] = [];
|
||||
@@ -175,9 +175,19 @@ const useUIStore = create(() => ({
|
||||
|
||||
const passthrough = ({ children }: React.PropsWithChildren) => <div>{children}</div>;
|
||||
|
||||
// Captured by value before the module is replaced: reading it back off the
|
||||
// namespace afterwards would resolve to the replacement and recurse.
|
||||
const { shouldPreserveManualModelOverride: realShouldPreserveManualModelOverride } =
|
||||
await import('@/lib/messages/userModelChoice');
|
||||
|
||||
mock.module('@/lib/messages/userModelChoice', () => ({
|
||||
findLatestUserModelChoice: () => latestUserChoice,
|
||||
shouldPreserveManualModelOverride: () => preserveManualOverride,
|
||||
// The real guard, unless a test opts out: whether it fires decides which
|
||||
// restore branch runs, and the branch that erased a recorded Default is the
|
||||
// one it declines to protect.
|
||||
shouldPreserveManualModelOverride: (args: Parameters<typeof realShouldPreserveManualModelOverride>[0]) => (
|
||||
forcePreserveManualOverride ?? realShouldPreserveManualModelOverride(args)
|
||||
),
|
||||
}));
|
||||
|
||||
mock.module('@/stores/useConfigStore', () => ({ useConfigStore }));
|
||||
@@ -316,7 +326,7 @@ describe('ModelControls effort restore', () => {
|
||||
variantWrites.length = 0;
|
||||
overrideWrites.length = 0;
|
||||
latestUserChoice = null;
|
||||
preserveManualOverride = false;
|
||||
forcePreserveManualOverride = null;
|
||||
useSelectionStore.setState({ savedVariant: undefined });
|
||||
useConfigStore.setState({
|
||||
currentProviderId: PROVIDER_ID,
|
||||
@@ -356,9 +366,32 @@ describe('ModelControls effort restore', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('the echo of a Default send does not erase the recorded Default', async () => {
|
||||
// The reported repro. The send under "Default" carried no effort, so the
|
||||
// message it echoes back carries none either, and its model matches the one
|
||||
// the send saved — which is exactly when the manual-override guard declines
|
||||
// to protect the selection and the history branch runs.
|
||||
latestUserChoice = { id: 'msg-echo', agent: AGENT, providerID: PROVIDER_ID, modelID: MODEL_ID };
|
||||
useSelectionStore.setState({ savedVariant: null });
|
||||
useConfigStore.setState({
|
||||
selectionSource: 'manual',
|
||||
settingsDefaultVariant: 'low',
|
||||
currentVariantSelection: { override: null, inherited: 'low' },
|
||||
});
|
||||
|
||||
const { cleanup } = await renderModelControls();
|
||||
try {
|
||||
expect(useSelectionStore.getState().savedVariant).toBeNull();
|
||||
expect(useConfigStore.getState().currentVariantSelection.override).toBeNull();
|
||||
expect(useConfigStore.getState().currentVariant).toBe(undefined);
|
||||
} finally {
|
||||
await cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
test('a preserved manual override keeps a recorded explicit Default', async () => {
|
||||
latestUserChoice = { id: 'msg-3', agent: AGENT, providerID: PROVIDER_ID, modelID: MODEL_ID, variant: 'high' };
|
||||
preserveManualOverride = true;
|
||||
forcePreserveManualOverride = true;
|
||||
useSelectionStore.setState({ savedVariant: null });
|
||||
useConfigStore.setState({ selectionSource: 'manual' });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user