Feat(GUI3): update preset while loaded (#2356)#2429
Conversation
Add an 'Update preset' action to the model detail panel that appears next to Unload when a loaded model has a different preset linked than the one it is running. Live-updateable changes (sampling, system prompt) apply without a reload; reload-requiring changes (recipe_options, engine hint) trigger an automatic reload flow with progress/status — no manual unload/load.
Adds client-local running-preset tracking and classifyPresetChange (live/reload/none) in presetStore, an api.updatePreset() hook against the proposed POST /api/v{0,1}/update-preset contract, polite aria-live feedback, focus management, and Playwright/axe coverage A154-A163. Real reload mechanics and the Lemonade-tools 'change the preset' wiring are deferred to the backend (lemond is off-limits to the UI POC); contract documented in docs/UPDATE_PRESET_CONTRACT.md.
Part of #2356
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@fl0rianr — whenever you have a moment, could you take a look at this PR for #2356? It's the UI/POC for update-preset-while-loaded (Update button next to Unload, live-vs-reload paths, full a11y, 178/7/0 tests green). I'd love your guidance on three things before the backend team wires up the real reload mechanics:
Full proposed contract is in |
|
I think the current API split is too complicated and puts the wrong responsibility on the UI. We probably do not need an update-preset endpoint with a client-provided mode: "live" | "reload". For request-time fields like system prompt, sampling/temperature and probably tools, the frontend can simply update the active preset binding and send those values with the next generation request. No model runtime state has to change and no backend reload is needed. Not at this point. For load-time fields like ctx_size, backend, device or model args, we need a real reload anyway. In that case the backend should either use the existing unload/load. The UI should not be the source of truth for runtime capability. You can name a reload function for a potential future backend change, but currently just execute a unload and a load afterwards like on main. Tools need adapting: Also, the current classifyPresetChange returns none when running.id === next.id, so editing an existing preset with the same ID will not surface an update even if temperature, system prompt or ctx changed. That seems like a correctness bug. Suggested simplification: UI stores linkedPresetId / active preset binding. I would appreciate lovell has a look as well before coming back to me. |
|
@fl0rianr — reviewed per your request. I agree with the simplification; it removes an endpoint we don't need and puts each field group where it already belongs. Confirmed: the Plan (Mattingly implements on this branch, tests stay green):
Blocking design questions:
— Lovell |
|
Regarding the blocking design questions:
|
…PresetChange (#2356) Per @fl0rianr review + Lovell's plan: - Fix classifyPresetChange: remove early same-id 'none' return so in-place edits classify as live/reload correctly - Remove api.updatePreset and the client mode param; add reloadModel() helper (unload+load) - Live (request-time) preset changes are a pure client-local rebind via request composition; no POST - Load-time changes reload the model; active-preset binding persists across reload - Add change_preset Lemonade tool driving the same workflow - Button labels: 'Apply preset' (live) / 'Reload to apply preset' (load-time) - Tests A154-A166 reworked/added; full suite 181 passed, 7 skipped Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@fl0rianr — implemented the simplified "update preset while loaded" design per your review feedback + Lovell''s plan. Pushed to PR #2429. What changed
Assumption I made on the open question (please confirm): the active-preset binding persists across the unload/reload — the UI rebinds before reloading so the reloaded model comes up running the newly-bound preset, and the Tests: reworked A154–A163 to the no-endpoint/no-mode flow and added A164–A166. Full Playwright suite: 181 passed, 7 skipped, 0 failed. — Mattingly |
|
@fl0rianr — thanks for confirming. I verified the shipped code matches both of your answers; no fix-up commit was needed (already correct as of 96739e1). (a) Load-time changes bind the new preset FIRST, then reload.
(b) Tools are request-time composition (live, no reload), alongside sampling + system prompt.
(c) Fix-up commit: none required — the ordering and tools-live classification were already correct as shipped. (d) Tests: full Playwright suite green — 181 passed, 7 skipped, 0 failed. Ready for your review / merge. — Mattingly |
Part of #2356.
What shipped (UI / POC)
Adds an "Update preset" action to the model detail panel that appears next to Unload when a model is loaded and a different preset is linked to it (linked ≠ running):
recipe_optionssuch as ctx_size/backend/device/args/steps, or the engine hint) trigger an automatic reload flow with a "Reloading…" spinner/status — the user never manually unloads/loads.running_presetsstore) +classifyPresetChange(running, next) → 'none' | 'live' | 'reload'inpresetStore.ts.api.updatePreset(modelName, presetId, mode, payload)hook against the proposedPOST /api/v{0,1}/update-presetcontract.Accessibility
<button>;aria-labelnames the model and states "(reloads the model)" for reload changes;aria-busywhile updating.role="status" aria-live="polite"region announces the outcome; sightedaria-hiddenhint explains why the button appeared.prefers-reduced-motion.Deferred to backend (lemond is off-limits to the UI POC)
window.api+ HTTP contract and the live-vs-reload field split are documented inprototype/ui-redesign/docs/UPDATE_PRESET_CONTRACT.md— @fl0rianr please confirm the contract + the field classification.Acceptance criteria satisfied in the POC
Tool-parity + real-reload criteria are deferred to backend (noted above).