feat(web): model settings popover in the LLM provider modal - #14131
Merged
Conversation
The slider, the setting row, and the reasoning stop constants were private to the chat model selector. The admin provider modal needs the same controls, so move them out rather than grow a second implementation. Pure move. maxSupportedReasoningStop stays behind as a one-line adapter over maxReasoningStop, since the admin side holds a raw ModelConfiguration rather than an LLMOption.
Adds a Model Settings popover to each model row in the provider setup modal, where an admin sets the reasoning cap, the reasoning default, and the temperature default for that model. The reasoning section renders only the levels the backend says the model distinguishes, and hides entirely for a reasoning model that takes no effort parameter. The temperature section hides for reasoning models, which the backend pins to 1. Dragging Max below Default pulls Default down with it, so the pair cannot be saved in a state the API rejects. Also carries the settings through the model-refresh merge. That merge kept only is_visible from prior form state, so refreshing the model list inside the modal would have discarded unsaved settings.
Contributor
Greptile SummaryThe PR adds per-model reasoning and temperature settings, default-model actions, and safer reconciliation of fetched model data in provider forms.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Provider model row] --> B[Rename model]
A --> C[Open model settings]
A --> D[Set as default]
C --> E[Update Formik model configuration]
F[Model refetch] --> G[Functional state reconciliation]
G --> E
E --> H[Submit provider configuration]
Reviews (5): Last reviewed commit: "fix(web): uniform range for the default ..." | Re-trigger Greptile |
Enabling auto-update restored the full initial model snapshot, discarding unsaved renames and admin settings along with the visibility it meant to reset. The restore now takes only visibility from the snapshot. Also names the ResetToAuto props interface per the frontend standards.
Contributor
🖼️ Visual Regression Report
|
The popover was 192px with the chat pane's full setting rows, so titles wrapped and value readouts clipped. Rebuilt to the mock's structure: 280px, one icon-and-caption header per section, small labeled sliders indented to the icon column, and stop labels under each slider with the active stop emphasized. Also tightens the model rows to the mock's compact height.
…r modal A provider saved with an empty custom_config object opened the custom provider form. The well-known route now requires custom config keys, not just a non-null object.
Custom provider rows get the same settings popover as well-known providers. The model rows carry the reasoning and temperature fields through the form so the popover can edit them.
Each visible model row gets the mock's hover action to make it the org default. The current default shows a static Default Model label instead. Saving uses the existing default-model endpoint and refreshes the provider caches.
Clicking an editable ContentMd title started the rename and also bubbled to the host row, which toggled the model's visibility.
Portaling the popover into the dialog made a tall popover overflow the dialog box, so the modal grew a second scrollbar. The popover now stays on the body portal and opens as a modal popover, which keeps its clicks and focus away from the dialog's dismiss and focus-trap layers.
The current default shows an always visible Default Model tag in the selection color. Other rows get a hover Set as Default internal button instead of a plain text action.
The toggle rebuilt the model list from the mount snapshot, so models a refetch discovered later vanished from the form. The restore now walks the current list and takes only visibility from the snapshot.
setMax compared the clamped display value, so a stored default above the model's current capability survived in form state and the API rejected the save. The comparison now uses the raw stored default.
CustomModal seeded the form with raw saved reasoning settings, so a capability that shrank since the save produced values the API rejects. The rows now pass through the same clamp as well-known providers.
Popover.Content caps its height at the available viewport space and clips overflow, so a short window cut off the temperature section. The content now scrolls inside the popover when it cannot fit.
The submit mapper dropped the reasoning and temperature fields and forced supports_reasoning to false, so popover edits on custom models saved as no-ops. The mapper now carries the fields through.
The caption and label wrappers rendered inline spans on the parent's 24px line box, inflating the popover past the viewport and forcing the scroll shell. Flex wrappers collapse the strut to the fonts' 16px lines, headers drop their bottom padding per the mock, and the scroll shell goes away since the popover now fits.
Extracts setDefaultLlmModelAndRefresh and withFetchedModels to kill duplicated blocks, clamps settings through maxReasoningStop so an unordered capability list cannot raise the ceiling, narrows the popover prop to the fields it reads, and keeps hover actions visible while the portaled popover is open. Also tightens stale or garbled comments.
Clicking the row to finish an inline rename blurs the edit input, which unmounts before the click reaches the row, so the interactive-element guard missed it and the model's visibility flipped. The row now samples the edit input's presence at pointerdown.
Contributor
Author
Contributor
|
Preview Deployment
|
2 tasks
The pointerdown sample matched any input in the row, and the checkbox always renders a hidden one, so every row click read as a rename commit and visibility toggling died. CI caught it in the provider setup specs.
Contributor
Author
The popover hand-rolled the section headers as raw divs, but the mock's headers are instances of the same design component ContentMd implements, so ContentAction renders them. The slider blocks become Sections with margin insets, since Section silences padding utilities. No raw layout elements remain.
Contributor
Author
The default slider's range shrank to the current max, so its thumb disagreed with the mark labels and lowering the max visibly dragged the default around. Both sliders now span every stop and only the input clamps to the cap, and an unset default parks at medium bounded by the cap.
Contributor
Author
raunakab
approved these changes
Aug 21, 2026
Every external edit trigger also wants the internal pencil gone, so the separate hideEditButton flag collapses into editHandle. Suggested by review.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds a Model Settings popover to each model row in the LLM provider setup modal, where an admin sets the reasoning cap, the reasoning default, and the temperature default for that model. Backend enforcement merged in #14078.
The first commit is a pure move: the slider, the setting row, and the reasoning stop constants were private to the chat model selector, and the admin side needs the same controls.
The popover offers only the levels the backend says the model distinguishes, hides the reasoning section for a reasoning model that takes no effort parameter, and disables temperature for reasoning models, which the backend pins to 1. Dragging Max below Default pulls Default down, so the pair cannot reach a state the API rejects. A stored setting is clamped by current capability on read, so a level the model lost since the save is neither shown nor resubmitted.
The model rows also gain the mock's set-as-default action: the current org default shows a Default Model tag, every other visible row gets a hover Set as Default button.
Pre-existing bugs in the surrounding code are fixed here, since the change sits on top of them:
is_visible.setValues.How Has This Been Tested?
bun run types:checkclean, oxfmt / oxlint / ripsecrets pass on every touched file.Demo (open modal, hover actions, popover, reasoning default change):
Before: the modal renders plain checkbox rows with no per-model controls. The popover, the hover actions, and the Default Model tag are all new surfaces.
Additional Options