diff --git a/apps/web/src/domains/settings/ai/manage-profiles-blocked-delete-modal.tsx b/apps/web/src/domains/settings/ai/manage-profiles-blocked-delete-modal.tsx
new file mode 100644
index 00000000000..52daed0f1bc
--- /dev/null
+++ b/apps/web/src/domains/settings/ai/manage-profiles-blocked-delete-modal.tsx
@@ -0,0 +1,124 @@
+import { Button } from "@vellum/design-library/components/button";
+import { Dropdown } from "@vellum/design-library/components/dropdown";
+import { Modal } from "@vellum/design-library/components/modal";
+import { Typography } from "@vellum/design-library/components/typography";
+
+import type { ProfileWithName } from "@/domains/settings/ai/ai-types";
+
+// ---------------------------------------------------------------------------
+// Types
+// ---------------------------------------------------------------------------
+
+export interface BlockedDeleteState {
+ name: string;
+ label: string;
+ isActive: boolean;
+ callSiteIds: string[];
+}
+
+// ---------------------------------------------------------------------------
+// BlockedDeleteModal
+// ---------------------------------------------------------------------------
+
+export function BlockedDeleteModal({
+ blocked,
+ availableReplacements,
+ replacement,
+ onReplacementChange,
+ error,
+ saving,
+ onClose,
+ onConfirm,
+}: {
+ blocked: BlockedDeleteState | null;
+ availableReplacements: ProfileWithName[];
+ replacement: string;
+ onReplacementChange: (value: string) => void;
+ error: string | null;
+ saving: boolean;
+ onClose: () => void;
+ onConfirm: () => void;
+}) {
+ let summary = "";
+ if (blocked) {
+ const display = blocked.label || blocked.name;
+ if (blocked.isActive && blocked.callSiteIds.length > 0) {
+ summary = `"${display}" is the active profile and is used by ${blocked.callSiteIds.length} call site(s). Pick a replacement profile.`;
+ } else if (blocked.isActive) {
+ summary = `"${display}" is the active profile. Pick a different active profile before deleting, or select a replacement below.`;
+ } else {
+ summary = `"${display}" is used by ${blocked.callSiteIds.length} call site(s). Select a replacement profile to reassign them before deleting.`;
+ }
+ }
+
+ return (
+ {
+ if (!next) onClose();
+ }}
+ >
+
+
+ Can't Delete Profile
+
+
+
+ {summary}
+
+ {blocked && blocked.callSiteIds.length > 0 && (
+
+ {blocked.callSiteIds.map((id) => (
+ -
+ •
{id}
+
+ ))}
+
+ )}
+
+
+ ({
+ value: p.name,
+ label: p.label ?? p.name,
+ })),
+ ]}
+ />
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/domains/settings/ai/manage-profiles-list-item.tsx b/apps/web/src/domains/settings/ai/manage-profiles-list-item.tsx
new file mode 100644
index 00000000000..0b65c30059d
--- /dev/null
+++ b/apps/web/src/domains/settings/ai/manage-profiles-list-item.tsx
@@ -0,0 +1,180 @@
+import { GripVertical, Trash2 } from "lucide-react";
+
+import { Button } from "@vellum/design-library/components/button";
+import { Tag } from "@vellum/design-library/components/tag";
+import { Toggle } from "@vellum/design-library/components/toggle";
+import { Typography } from "@vellum/design-library/components/typography";
+
+import type { ProfileWithName } from "@/domains/settings/ai/ai-types";
+import { AUTO_PROFILE_NAME } from "@/domains/settings/ai/profile-pickers";
+
+// ---------------------------------------------------------------------------
+// Types
+// ---------------------------------------------------------------------------
+
+interface DropTarget {
+ name: string;
+ after: boolean;
+}
+
+interface ProfileListItemProps {
+ profile: ProfileWithName;
+ isDragging: boolean;
+ dropTarget: DropTarget | null;
+ isDeleting: boolean;
+ deleteError: string | undefined;
+ isToggling: boolean;
+ onDragStart: (e: React.DragEvent) => void;
+ onDragEnd: () => void;
+ onDragOver: (e: React.DragEvent) => void;
+ onDragLeave: (e: React.DragEvent) => void;
+ onDrop: (e: React.DragEvent) => void;
+ onEditClick: () => void;
+ onDeleteClick: () => void;
+ onStatusToggle: (active: boolean) => void;
+}
+
+// ---------------------------------------------------------------------------
+// ProfileListItem
+// ---------------------------------------------------------------------------
+
+export function ProfileListItem({
+ profile,
+ isDragging,
+ dropTarget,
+ isDeleting,
+ deleteError,
+ isToggling,
+ onDragStart,
+ onDragEnd,
+ onDragOver,
+ onDragLeave,
+ onDrop,
+ onEditClick,
+ onDeleteClick,
+ onStatusToggle,
+}: ProfileListItemProps) {
+ const isManaged = profile.source === "managed";
+ const isActive = profile.status !== "disabled";
+ const isAutoProfile = profile.name === AUTO_PROFILE_NAME;
+
+ return (
+
+ {dropTarget?.name === profile.name && !dropTarget.after && (
+
+ )}
+
+ {/* Grip icon — invisible for managed profiles to preserve alignment */}
+
+
+ {/* Label — dimmed when disabled */}
+
+
+
+ {profile.label ?? profile.name}
+
+ {isManaged && profile.name !== AUTO_PROFILE_NAME && (
+
+ Platform
+
+ )}
+
+ {profile.description ? (
+
+ {profile.description}
+
+ ) : null}
+ {(profile.model ?? profile.provider) ? (
+
+ {profile.model ?? profile.provider}
+
+ ) : null}
+
+
+ {/* Actions */}
+
+
+ onStatusToggle(next)}
+ disabled={isToggling}
+ aria-label={`${isActive ? "Disable" : "Enable"} ${profile.label ?? profile.name}`}
+ />
+
+
+
+ }
+ aria-label={`Delete ${profile.label ?? profile.name}`}
+ disabled={isManaged || isDeleting}
+ title={
+ isManaged ? "Managed profiles cannot be deleted" : undefined
+ }
+ onClick={onDeleteClick}
+ tintColor="var(--system-negative-strong)"
+ />
+
+
+
+ {dropTarget?.name === profile.name && dropTarget.after && (
+
+ )}
+ {deleteError ? (
+
+ {deleteError}
+
+ ) : null}
+ {profile.name === AUTO_PROFILE_NAME && (
+
+ )}
+
+ );
+}
diff --git a/apps/web/src/domains/settings/ai/manage-profiles-modal.tsx b/apps/web/src/domains/settings/ai/manage-profiles-modal.tsx
index 57f17369b8f..17fe7223bb6 100644
--- a/apps/web/src/domains/settings/ai/manage-profiles-modal.tsx
+++ b/apps/web/src/domains/settings/ai/manage-profiles-modal.tsx
@@ -1,38 +1,26 @@
-import { GripVertical, Trash2 } from "lucide-react";
import { useMemo, useRef, useState } from "react";
-import { useQuery, useQueryClient } from "@tanstack/react-query";
+import { useQuery } from "@tanstack/react-query";
import { Button } from "@vellum/design-library/components/button";
-import { Dropdown } from "@vellum/design-library/components/dropdown";
-import { Toggle } from "@vellum/design-library/components/toggle";
import { Modal } from "@vellum/design-library/components/modal";
-import { Tag } from "@vellum/design-library/components/tag";
import { Typography } from "@vellum/design-library/components/typography";
import { useAssistantFeatureFlagStore } from "@/stores/assistant-feature-flag-store";
import { captureError } from "@/lib/sentry/capture-error";
-import type { CallSiteOverrideDraft, DaemonConfig, DaemonConfigPatch, ProfileEntry, ProfileStatus, ProfileWithName } from "@/domains/settings/ai/ai-types";
+import type { CallSiteOverrideDraft, DaemonConfigPatch, ProfileEntry, ProfileStatus, ProfileWithName } from "@/domains/settings/ai/ai-types";
+import { BlockedDeleteModal } from "@/domains/settings/ai/manage-profiles-blocked-delete-modal";
+import type { BlockedDeleteState } from "@/domains/settings/ai/manage-profiles-blocked-delete-modal";
+import { ProfileListItem } from "@/domains/settings/ai/manage-profiles-list-item";
import { ProfileEditorModal } from "@/domains/settings/ai/profile-editor-modal";
-import {
- AUTO_PROFILE_NAME,
- gateAutoProfile,
-} from "@/domains/settings/ai/profile-pickers";
+import { gateAutoProfile } from "@/domains/settings/ai/profile-pickers";
import { inferenceProviderconnectionsGetOptions } from "@/generated/daemon/@tanstack/react-query.gen";
import { filterFlaggedConnections } from "@/domains/settings/ai/provider-connections-client";
import { useDaemonConfigQuery, useDaemonConfigMutation } from "@/domains/settings/ai/use-daemon-config";
-import { assistantDaemonConfigQueryKey } from "@/lib/sync/query-tags";
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
-interface BlockedDeleteState {
- name: string;
- label: string;
- isActive: boolean;
- callSiteIds: string[];
-}
-
interface ManageProfilesModalProps {
isOpen: boolean;
assistantId: string;
@@ -149,7 +137,6 @@ export function ManageProfilesModal({
profileOrder={profileOrder}
orderedProfiles={orderedProfiles}
activeProfile={activeProfile}
- assistantId={assistantId}
callSiteOverrides={callSites}
onClose={onClose}
onEditClick={(profile) => {
@@ -196,7 +183,6 @@ interface ManageProfilesModalInnerProps {
profileOrder: string[];
orderedProfiles: ProfileWithName[];
activeProfile: string | null;
- assistantId: string;
callSiteOverrides: Record;
onClose: () => void;
onEditClick: (profile: ProfileWithName) => void;
@@ -208,15 +194,12 @@ function ManageProfilesModalInner({
profileOrder,
orderedProfiles,
activeProfile,
- assistantId,
callSiteOverrides,
onClose,
onEditClick,
onNewClick,
}: ManageProfilesModalInnerProps) {
const configMutation = useDaemonConfigMutation();
- const queryClient = useQueryClient();
- const queryKey = assistantDaemonConfigQueryKey(assistantId);
const [deleteErrors, setDeleteErrors] = useState>({});
const [deleting, setDeleting] = useState>({});
@@ -227,7 +210,6 @@ function ManageProfilesModalInner({
const [draggingName, setDraggingName] = useState(null);
const [dropTarget, setDropTarget] = useState<{ name: string; after: boolean } | null>(null);
const [reorderError, setReorderError] = useState(null);
- const lastConfirmedOrderRef = useRef(profileOrder);
const draggingNameRef = useRef(null);
const dropTargetRef = useRef<{ name: string; after: boolean } | null>(null);
@@ -253,8 +235,7 @@ function ManageProfilesModalInner({
setToggleError(null);
const wireStatus: ProfileStatus = active ? "active" : "disabled";
- const previousEntry = profiles[profile.name];
- if (!previousEntry) {
+ if (!profiles[profile.name]) {
setTogglingNames((prev) => {
const next = new Set(prev);
next.delete(profile.name);
@@ -263,25 +244,6 @@ function ManageProfilesModalInner({
return false;
}
- // Cancel in-flight refetches so they don't overwrite the optimistic update.
- // See: https://tkdodo.eu/blog/concurrent-optimistic-updates-in-react-query
- await queryClient.cancelQueries({ queryKey });
-
- const previousStatus = previousEntry.status ?? "active";
- queryClient.setQueryData(queryKey, (old) => {
- if (!old?.llm?.profiles?.[profile.name]) return old;
- return {
- ...old,
- llm: {
- ...old.llm,
- profiles: {
- ...old.llm.profiles,
- [profile.name]: { ...old.llm.profiles[profile.name], status: wireStatus },
- },
- },
- };
- });
-
try {
await configMutation.mutateAsync({
llm: { profiles: { [profile.name]: { status: wireStatus } } },
@@ -289,20 +251,6 @@ function ManageProfilesModalInner({
return true;
} catch (error) {
captureError(error, { context: "settings-ai-profile-toggle" });
- // Rollback only the toggled field to avoid overwriting concurrent cache updates
- queryClient.setQueryData(queryKey, (old) => {
- if (!old?.llm?.profiles?.[profile.name]) return old;
- return {
- ...old,
- llm: {
- ...old.llm,
- profiles: {
- ...old.llm.profiles,
- [profile.name]: { ...old.llm.profiles[profile.name], status: previousStatus },
- },
- },
- };
- });
setToggleError(
`Couldn't update "${profile.label ?? profile.name}". Please try again.`,
);
@@ -414,30 +362,10 @@ function ManageProfilesModalInner({
...without.slice(insertAt),
];
- // Cancel in-flight refetches so they don't overwrite the optimistic update.
- await queryClient.cancelQueries({ queryKey });
-
- queryClient.setQueryData(queryKey, (old) => {
- if (!old?.llm) return old;
- return {
- ...old,
- llm: { ...old.llm, profileOrder: newOrder },
- };
- });
-
try {
await configMutation.mutateAsync({ llm: { profileOrder: newOrder } });
- lastConfirmedOrderRef.current = newOrder;
} catch (error) {
captureError(error, { context: "settings-ai-profile-reorder" });
- // Rollback to last confirmed server state
- queryClient.setQueryData(queryKey, (old) => {
- if (!old?.llm) return old;
- return {
- ...old,
- llm: { ...old.llm, profileOrder: lastConfirmedOrderRef.current },
- };
- });
setReorderError("Failed to reorder profiles. Please try again.");
}
}
@@ -472,173 +400,61 @@ function ManageProfilesModalInner({
) : (
- {allOrderedProfiles.map((profile) => {
- const isManaged = profile.source === "managed";
- const isDeleting = deleting[profile.name] ?? false;
- const deleteError = deleteErrors[profile.name];
-
- const isActive = profile.status !== "disabled";
- const isToggling = togglingNames.has(profile.name);
- const isAutoProfile = profile.name === AUTO_PROFILE_NAME;
-
- return (
-
- {dropTarget?.name === profile.name && !dropTarget.after && (
-
- )}
-
{
- draggingNameRef.current = profile.name;
- setDraggingName(profile.name);
- if (e.dataTransfer) {
- e.dataTransfer.effectAllowed = "move";
- }
- }}
- onDragEnd={() => {
- draggingNameRef.current = null;
- dropTargetRef.current = null;
- setDraggingName(null);
- setDropTarget(null);
- }}
- onDragOver={(e) => {
- e.preventDefault();
- const rect = e.currentTarget.getBoundingClientRect();
- const after = e.clientY > rect.top + rect.height / 2;
- const t = { name: profile.name, after };
- dropTargetRef.current = t;
- setDropTarget(t);
- }}
- onDragLeave={(e) => {
- if (!e.currentTarget.contains(e.relatedTarget as Node | null)) {
- dropTargetRef.current = null;
- setDropTarget((prev) =>
- prev?.name === profile.name ? null : prev,
- );
- }
- }}
- onDrop={(e) => {
- e.preventDefault();
- const source = draggingNameRef.current;
- const target = dropTargetRef.current;
- draggingNameRef.current = null;
- dropTargetRef.current = null;
- setDraggingName(null);
- setDropTarget(null);
- if (source && target) {
- void handleReorder(source, target);
- }
- }}
- >
- {/* Grip icon — invisible for managed profiles to preserve alignment */}
-
-
- {/* Label — dimmed when disabled */}
-
-
-
- {profile.label ?? profile.name}
-
- {isManaged && profile.name !== AUTO_PROFILE_NAME && (
-
- Platform
-
- )}
-
- {profile.description ? (
-
- {profile.description}
-
- ) : null}
- {(profile.model ?? profile.provider) ? (
-
- {profile.model ?? profile.provider}
-
- ) : null}
-
-
- {/* Actions */}
-
-
-
- void handleStatusToggle(profile, next)
- }
- disabled={isToggling}
- aria-label={`${isActive ? "Disable" : "Enable"} ${profile.label ?? profile.name}`}
- />
-
-
-
- }
- aria-label={`Delete ${profile.label ?? profile.name}`}
- disabled={isManaged || isDeleting}
- title={
- isManaged ? "Managed profiles cannot be deleted" : undefined
- }
- onClick={() => handleDeleteClick(profile.name)}
- tintColor="var(--system-negative-strong)"
- />
-
-
-
- {dropTarget?.name === profile.name && dropTarget.after && (
-
- )}
- {deleteError ? (
-
- {deleteError}
-
- ) : null}
- {profile.name === AUTO_PROFILE_NAME && (
-
- )}
-
- );
- })}
+ {allOrderedProfiles.map((profile) => (
+
{
+ draggingNameRef.current = profile.name;
+ setDraggingName(profile.name);
+ if (e.dataTransfer) {
+ e.dataTransfer.effectAllowed = "move";
+ }
+ }}
+ onDragEnd={() => {
+ draggingNameRef.current = null;
+ dropTargetRef.current = null;
+ setDraggingName(null);
+ setDropTarget(null);
+ }}
+ onDragOver={(e) => {
+ e.preventDefault();
+ const rect = e.currentTarget.getBoundingClientRect();
+ const after = e.clientY > rect.top + rect.height / 2;
+ const t = { name: profile.name, after };
+ dropTargetRef.current = t;
+ setDropTarget(t);
+ }}
+ onDragLeave={(e) => {
+ if (!e.currentTarget.contains(e.relatedTarget as Node | null)) {
+ dropTargetRef.current = null;
+ setDropTarget((prev) =>
+ prev?.name === profile.name ? null : prev,
+ );
+ }
+ }}
+ onDrop={(e) => {
+ e.preventDefault();
+ const source = draggingNameRef.current;
+ const target = dropTargetRef.current;
+ draggingNameRef.current = null;
+ dropTargetRef.current = null;
+ setDraggingName(null);
+ setDropTarget(null);
+ if (source && target) {
+ void handleReorder(source, target);
+ }
+ }}
+ onEditClick={() => onEditClick(profile)}
+ onDeleteClick={() => handleDeleteClick(profile.name)}
+ onStatusToggle={(next) => void handleStatusToggle(profile, next)}
+ />
+ ))}
)}
{reorderError && (
@@ -687,110 +503,3 @@ function ManageProfilesModalInner({
>
);
}
-
-// ---------------------------------------------------------------------------
-// BlockedDeleteModal
-// ---------------------------------------------------------------------------
-
-function BlockedDeleteModal({
- blocked,
- availableReplacements,
- replacement,
- onReplacementChange,
- error,
- saving,
- onClose,
- onConfirm,
-}: {
- blocked: BlockedDeleteState | null;
- availableReplacements: ProfileWithName[];
- replacement: string;
- onReplacementChange: (value: string) => void;
- error: string | null;
- saving: boolean;
- onClose: () => void;
- onConfirm: () => void;
-}) {
- let summary = "";
- if (blocked) {
- const display = blocked.label || blocked.name;
- if (blocked.isActive && blocked.callSiteIds.length > 0) {
- summary = `"${display}" is the active profile and is used by ${blocked.callSiteIds.length} call site(s). Pick a replacement profile.`;
- } else if (blocked.isActive) {
- summary = `"${display}" is the active profile. Pick a different active profile before deleting, or select a replacement below.`;
- } else {
- summary = `"${display}" is used by ${blocked.callSiteIds.length} call site(s). Select a replacement profile to reassign them before deleting.`;
- }
- }
-
- return (
- {
- if (!next) onClose();
- }}
- >
-
-
- Can't Delete Profile
-
-
-
- {summary}
-
- {blocked && blocked.callSiteIds.length > 0 && (
-
- {blocked.callSiteIds.map((id) => (
- -
- •
{id}
-
- ))}
-
- )}
-
-
- ({
- value: p.name,
- label: p.label ?? p.name,
- })),
- ]}
- />
-
- {error && (
-
- {error}
-
- )}
-
-
-
-
-
-
-
- );
-}