Keep composer mode preferences stable (#1658)
* fix(app): preserve composer mode preferences Treat undefined provider preference updates as no-ops, and keep saved mode selections instead of silently defaulting them when provider metadata is incomplete or does not list the saved mode. * fix(app): document mode preference preservation
This commit is contained in:
@@ -81,6 +81,39 @@ describe("create agent preferences", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("does not erase a saved mode when a later partial update has no mode", () => {
|
||||
expect(
|
||||
mergeProviderPreferences({
|
||||
preferences: {
|
||||
provider: "codex",
|
||||
providerPreferences: {
|
||||
codex: {
|
||||
model: "gpt-5.5",
|
||||
mode: "full-access",
|
||||
thinkingByModel: { "gpt-5.5": "high" },
|
||||
},
|
||||
},
|
||||
},
|
||||
provider: "codex",
|
||||
updates: {
|
||||
model: "gpt-5.6",
|
||||
mode: undefined,
|
||||
thinkingByModel: undefined,
|
||||
featureValues: undefined,
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
provider: "codex",
|
||||
providerPreferences: {
|
||||
codex: {
|
||||
model: "gpt-5.6",
|
||||
mode: "full-access",
|
||||
thinkingByModel: { "gpt-5.5": "high" },
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("loads invalid stored preferences as empty preferences", () => {
|
||||
expect(parseFormPreferences({ providerPreferences: { codex: { mode: 42 } } })).toEqual({});
|
||||
});
|
||||
|
||||
@@ -46,6 +46,43 @@ export function parseFormPreferences(value: unknown): FormPreferences {
|
||||
return result.success ? result.data : DEFAULT_FORM_PREFERENCES;
|
||||
}
|
||||
|
||||
function mergeDefinedRecord<T>(
|
||||
existing: Record<string, T> | undefined,
|
||||
updates: Record<string, T> | undefined,
|
||||
): Record<string, T> | undefined {
|
||||
if (updates === undefined) {
|
||||
return existing;
|
||||
}
|
||||
return {
|
||||
...existing,
|
||||
...updates,
|
||||
};
|
||||
}
|
||||
|
||||
function applyProviderPreferenceUpdates(
|
||||
existing: ProviderPreferences,
|
||||
updates: Partial<ProviderPreferences>,
|
||||
): ProviderPreferences {
|
||||
const next: ProviderPreferences = { ...existing };
|
||||
const nextThinkingByModel = mergeDefinedRecord(existing.thinkingByModel, updates.thinkingByModel);
|
||||
const nextFeatureValues = mergeDefinedRecord(existing.featureValues, updates.featureValues);
|
||||
|
||||
if (updates.model !== undefined) {
|
||||
next.model = updates.model;
|
||||
}
|
||||
if (updates.mode !== undefined) {
|
||||
next.mode = updates.mode;
|
||||
}
|
||||
if (nextThinkingByModel !== undefined) {
|
||||
next.thinkingByModel = nextThinkingByModel;
|
||||
}
|
||||
if (nextFeatureValues !== undefined) {
|
||||
next.featureValues = nextFeatureValues;
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
export function mergeProviderPreferences(args: {
|
||||
preferences: FormPreferences;
|
||||
provider: AgentProvider;
|
||||
@@ -54,32 +91,13 @@ export function mergeProviderPreferences(args: {
|
||||
const { preferences, provider, updates } = args;
|
||||
const existingProviderPreferences = preferences.providerPreferences ?? {};
|
||||
const existing = existingProviderPreferences[provider] ?? {};
|
||||
const nextThinkingByModel =
|
||||
updates.thinkingByModel === undefined
|
||||
? existing.thinkingByModel
|
||||
: {
|
||||
...existing.thinkingByModel,
|
||||
...updates.thinkingByModel,
|
||||
};
|
||||
const nextFeatureValues =
|
||||
updates.featureValues === undefined
|
||||
? existing.featureValues
|
||||
: {
|
||||
...existing.featureValues,
|
||||
...updates.featureValues,
|
||||
};
|
||||
|
||||
return {
|
||||
...preferences,
|
||||
provider,
|
||||
providerPreferences: {
|
||||
...existingProviderPreferences,
|
||||
[provider]: {
|
||||
...existing,
|
||||
...updates,
|
||||
...(nextThinkingByModel ? { thinkingByModel: nextThinkingByModel } : {}),
|
||||
...(nextFeatureValues ? { featureValues: nextFeatureValues } : {}),
|
||||
},
|
||||
[provider]: applyProviderPreferenceUpdates(existing, updates),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user