fix(desktop,dashboard): single-key config writers send a sparse patch, not the cached snapshot
Applying a reasoning/speed default in Desktop Settings -> Model reset an auxiliary slot a user had pinned via CLI back to provider "auto" / model "" while leaving reasoning_effort intact (#95460). POST /api/model/set was never the writer; writeAgentDefault was: it round-tripped the whole default-expanded config record (loaded when Settings opened) through PUT /api/config, so every key another surface changed since the snapshot was echoed back with its stale, default-filled value. The pinned slot's provider/model existed only as defaults in the snapshot; reasoning_effort was already in it, hence the asymmetry the report observed. PUT /api/config deep-merges onto disk, so a writer only needs to send the key it changed. Every desktop single-key writer now does exactly that (the config-settings page already diffed against a baseline): Model defaults (agent.reasoning_effort / service_tier), Appearance resume_last_session, terminal font, session auto-archive, the two browser.use_real_profile toggles, and the Capabilities voice fields (diffConfig against a baseline). The optimistic shared-cache write keeps the full merged record so sibling surfaces repaint without a refetch. The dashboard's ReasoningPicker had the same read-modify-write shape and now sends the sparse patch too. Tests pin the wire contract: only the edited key is sent, a sibling pin that is not in the snapshot cannot be echoed back.
This commit is contained in:
@@ -77,20 +77,12 @@ export function ReasoningPicker({
|
||||
const prev = effort;
|
||||
setEffort(next); // optimistic
|
||||
setSaving(true);
|
||||
// Read-modify-write the whole config — the dashboard's single-key save
|
||||
// pattern — so we never clobber sibling keys. `saveConfig` PUTs the full
|
||||
// object the agent boots from.
|
||||
// Sparse patch: PUT /api/config deep-merges onto disk, so sending only
|
||||
// the edited key never clobbers sibling keys — and never echoes a
|
||||
// default-expanded snapshot back over values another surface changed
|
||||
// meanwhile (a CLI-pinned auxiliary slot would come back as "auto").
|
||||
void api
|
||||
.getConfig(profile)
|
||||
.then((cfg) => {
|
||||
const base = (cfg ?? {}) as Record<string, unknown>;
|
||||
const agent =
|
||||
base.agent && typeof base.agent === "object"
|
||||
? { ...(base.agent as Record<string, unknown>) }
|
||||
: {};
|
||||
agent.reasoning_effort = next;
|
||||
return api.saveConfig({ ...base, agent }, profile);
|
||||
})
|
||||
.saveConfig({ agent: { reasoning_effort: next } }, profile)
|
||||
.then(() => {
|
||||
onChanged?.(next);
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user