feat(site/src): add advisor admin settings UI by ThomasK33 · Pull Request #24624 · coder/coder
This was referenced
ThomasK33
changed the base branch from
feat/advisor-03-config-api
to
graphite-base/24624
ThomasK33
changed the base branch from
graphite-base/24624
to
feat/advisor-03-config-api
ThomasK33
changed the title
feat(site/src/pages/AgentsPage): add advisor admin settings UI
feat(site/src): add advisor admin settings UI
ThomasK33
changed the base branch from
feat/advisor-03-config-api
to
graphite-base/24624
graphite-app
Bot
changed the base branch from
graphite-base/24624
to
main
Adds an admin-only "Advisor" section to the Agent Settings → Behavior page, following the Virtual Desktop pattern. - API client methods and TanStack Query hooks for the advisor config endpoint, with automatic cache invalidation on save. - AdvisorSettings component: toggle + max uses per run (0 = unlimited) + max output tokens + reasoning effort dropdown + advisor model override dropdown. - Storybook stories covering enabled/disabled/saving/error. - Wires the section into AgentSettingsBehaviorPage + its view, with updated page and page-view stories. Uses generated AdvisorConfig / UpdateAdvisorConfigRequest types from codersdk. Handles the zero UUID as the "use chat model" sentinel for both reads and writes. Signed-off-by: Thomas Kosiewski <tk@coder.com> --- _Generated with `mux`_
…rrides fail to load Change-Id: I521233cf90e70aea4876b6686bae629bfed234e0 Signed-off-by: Thomas Kosiewski <tk@coder.com>
- Add missing isAdvisorConfigFetching prop default in parent stories to unblock the tsc lint CI check (DEREM-25). - Show "Loading..." instead of the "Unavailable model" fallback on the advisor model trigger while model configs are still being fetched (DEREM-15). - Skip numeric/reasoning validation when the advisor feature is disabled so admins can persist the disable action even when hidden fields are in an invalid state. - Add Storybook stories for the refetching, loading-model-configs, and model-configs-error branches (DEREM-26, DEREM-27).
…display name is blank Model configs may have an empty display_name because the backend trims without enforcing a non-empty fallback. Use the same display_name.trim() || model pattern already used by ExploreModelOverrideSettings for both the option list and the selected trigger label so admins never see a blank advisor model entry. Change-Id: I870a2a97757e2af1728dc1aa45686cd932b777fe Signed-off-by: Thomas Kosiewski <tk@coder.com>
Preserve stored advisor limits when saving with the advisor disabled so that hidden, invalid mid-edit values cannot silently overwrite the server-side configuration on re-enable. Surface backend error detail in the inline save error via getErrorMessage so admins can distinguish between the advisor config's validation failure modes. Add stories that exercise the enable-then-disable-then-save path and the detailed save error rendering. Change-Id: I31eabc40b604e7b18a840b348197a01da097f5f6 Signed-off-by: Thomas Kosiewski <tk@coder.com>
Track the most recently committed advisor values via a ref so the disable-path payload no longer reads from the potentially stale advisorConfigData query snapshot. This prevents recently saved limits and model selections from being silently rolled back when the user disables the advisor before a refetch completes or when the refetch fails. Add a story that exercises deselecting a real advisor model back to the chat-model fallback so the reverse direction of the model dropdown is covered by the play function suite. Change-Id: I5f3c1d9ad4f2b1c7e9b8a5c2d1e0f6a4b3c2d1e0 Signed-off-by: Thomas Kosiewski <tk@coder.com>
… disable Clearing the model override when disabling prevents the save from failing with a 400 when the previously stored model config has been deleted. Adds stories covering the disable-with-deleted-model path and client-side validation blocking Save on dirty-but-invalid input. Change-Id: I988bc240f102841f1428f8b940ce5d979fcb05dd Signed-off-by: Thomas Kosiewski <tk@coder.com>
…en when model configs fail to load When an admin disables the advisor and the saved model override references a model that no longer exists, the backend rejects the stale ID with a 400. The previous guard only cleared the override when `modelConfigsError` was falsy, so a failing model-configs query left the admin unable to disable the advisor. Drop the `!modelConfigsError` check so the override is scrubbed whenever the current list (cached or freshly fetched) does not contain the stored ID. Add `DisableAdvisorWithDeletedModelAndModelConfigsError` to prove the payload carries `model_config_id: nilUUID` in this edge case. Change-Id: Ie0e8e34a45351f3b87e1a4cacd9e127c6f15e543 Signed-off-by: Thomas Kosiewski <tk@coder.com>
…ring loading Previously, the disable guard skipped stale-ID cleanup while the model-configs query was still loading, so racing a disable against the in-flight fetch forwarded a deleted model_config_id and the backend rejected the request with a 400. Drop the loading guard so disable stays reliable in that race; the rationale for clearing when nothing can be verified in the cache already applied to the failing fetch case. Change-Id: I7284d62df7f3372dc5f20fa58b214e926941f682 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
Addresses DEREM-32 and DEREM-33 from the round 11 agent review. DEREM-32 (P0): Formik's `handleChange` parses `type="number"` inputs with `parseFloat`, which replaced the declared `string` form value with a `number` at runtime. `isNonNegativeIntegerString` then threw on `.trim()` for every numeric keystroke, freezing `form.errors` and pinning Save as disabled. Write the raw `event.currentTarget.value` string via `setFieldValue` on both numeric inputs to keep the runtime value aligned with `AdvisorSettingsFormValues`. DEREM-33 (P3): The stale-model scrub on disable also fired during initial page load when `modelConfigs` was still `[]`, silently clearing a valid override when the admin disabled before the query settled. Narrow the scrub to only run when model configs have loaded successfully and the list is non-empty, so an in-flight or failing fetch forwards the override unchanged and the backend can surface a specific 400 if the ID really has been deleted. Rename and rework the two stories that previously asserted the aggressive scrub to instead assert the override is preserved during load and on error. Signed-off-by: Thomas Kosiewski <tk@coder.com>
…en model list is empty Disabling the advisor with a deleted model_config_id and zero model configs would forward the stale UUID and fail the save with a 400. The loading and error guards already cover the "not loaded yet" case, so an empty list after a successful load is a definitive answer that the override is missing. Add a story that locks in the recovery path. Change-Id: I2be12c3228419c6cd62e4979bdc4d0d29c38102f Signed-off-by: Thomas Kosiewski <tk@coder.com>
react-query keeps `isLoading` false during background refetches when cached data exists, so the disable-path scrub could decide from stale model data and either preserve a now-deleted override (causing a 400 on save) or silently drop a still-valid override missing from a stale cache. Gate the scrub on `isFetching` as well so refetches are treated as indeterminate. Change-Id: I7123032f2671c6e0ba454835b521d4c0e57c452d Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
ThomasK33
deleted the
feat/advisor-06-admin-settings-ui
branch