From 0bccdedb4f32019fb4b8962f5a6a02a8aab5b0cc Mon Sep 17 00:00:00 2001 From: "Abdullah." <125115953+mabdullahabaid@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:41:26 +0500 Subject: [PATCH] feat: design the ai-models tab on settings ai page (#18147) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove AI model selectors from the settings tab on AI settings page, rename that tab to "More" and create a separate "Models" tab as per the design. https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=91311-278313&m=dev --------- Co-authored-by: Félix Malfait --- .../src/pages/settings/ai/SettingsAI.tsx | 23 +- .../ai/components/SettingsAIModelsTab.tsx | 105 +++++++++ .../components/SettingsAIRouterSettings.tsx | 220 ------------------ .../ai/constants/SettingsAiModelProviders.ts | 23 ++ .../settings/ai/constants/SettingsAiTabs.ts | 3 +- .../twenty-ui/src/assets/icons/anthropic.svg | 3 + packages/twenty-ui/src/assets/icons/groq.svg | 6 + .../twenty-ui/src/assets/icons/mistral.svg | 14 ++ packages/twenty-ui/src/assets/icons/xai.svg | 8 + .../icon/components/IconBrandAnthropic.tsx | 19 ++ .../display/icon/components/IconBrandGroq.tsx | 19 ++ .../icon/components/IconBrandMistral.tsx | 19 ++ .../display/icon/components/IconBrandXai.tsx | 19 ++ .../display/icon/components/TablerIcons.ts | 2 + packages/twenty-ui/src/display/index.ts | 6 + 15 files changed, 260 insertions(+), 229 deletions(-) create mode 100644 packages/twenty-front/src/pages/settings/ai/components/SettingsAIModelsTab.tsx delete mode 100644 packages/twenty-front/src/pages/settings/ai/components/SettingsAIRouterSettings.tsx create mode 100644 packages/twenty-front/src/pages/settings/ai/constants/SettingsAiModelProviders.ts create mode 100644 packages/twenty-ui/src/assets/icons/anthropic.svg create mode 100644 packages/twenty-ui/src/assets/icons/groq.svg create mode 100644 packages/twenty-ui/src/assets/icons/mistral.svg create mode 100644 packages/twenty-ui/src/assets/icons/xai.svg create mode 100644 packages/twenty-ui/src/display/icon/components/IconBrandAnthropic.tsx create mode 100644 packages/twenty-ui/src/display/icon/components/IconBrandGroq.tsx create mode 100644 packages/twenty-ui/src/display/icon/components/IconBrandMistral.tsx create mode 100644 packages/twenty-ui/src/display/icon/components/IconBrandXai.tsx diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx index 3403ff0003..fd025d016b 100644 --- a/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx +++ b/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx @@ -13,15 +13,16 @@ import { getSettingsPath } from 'twenty-shared/utils'; import { t } from '@lingui/core/macro'; import { H2Title, + IconCpu, IconFileText, - IconSettings, + IconSettingsBolt, IconSparkles, IconTool, } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Card, Section } from 'twenty-ui/layout'; import { SettingsAIMCP } from './components/SettingsAIMCP'; -import { SettingsAIRouterSettings } from './components/SettingsAIRouterSettings'; +import { SettingsAIModelsTab } from './components/SettingsAIModelsTab'; import { SettingsSkillsTable } from './components/SettingsSkillsTable'; import { SettingsToolsTable } from './components/SettingsToolsTable'; import { SETTINGS_AI_TABS } from './constants/SettingsAiTabs'; @@ -37,6 +38,11 @@ export const SettingsAI = () => { ); const tabs = [ + { + id: SETTINGS_AI_TABS.TABS_IDS.MODELS, + title: t`Models`, + Icon: IconCpu, + }, { id: SETTINGS_AI_TABS.TABS_IDS.SKILLS, title: t`Skills`, @@ -48,15 +54,16 @@ export const SettingsAI = () => { Icon: IconTool, }, { - id: SETTINGS_AI_TABS.TABS_IDS.SETTINGS, - title: t`Settings`, - Icon: IconSettings, + id: SETTINGS_AI_TABS.TABS_IDS.MORE, + title: t`More`, + Icon: IconSettingsBolt, }, ]; + const isModelsTab = activeTabId === SETTINGS_AI_TABS.TABS_IDS.MODELS; const isSkillsTab = activeTabId === SETTINGS_AI_TABS.TABS_IDS.SKILLS; const isToolsTab = activeTabId === SETTINGS_AI_TABS.TABS_IDS.TOOLS; - const isSettingsTab = activeTabId === SETTINGS_AI_TABS.TABS_IDS.SETTINGS; + const isMoreTab = activeTabId === SETTINGS_AI_TABS.TABS_IDS.MORE; return ( { tabs={tabs} componentInstanceId={SETTINGS_AI_TABS.COMPONENT_INSTANCE_ID} /> + {isModelsTab && } {isSkillsTab && } {isToolsTab && } - {isSettingsTab && ( + {isMoreTab && ( <> -
= new Set([ + DEFAULT_SMART_MODEL, + DEFAULT_FAST_MODEL, +]); + +export const SettingsAIModelsTab = () => { + const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar(); + const [currentWorkspace, setCurrentWorkspace] = useRecoilState( + currentWorkspaceState, + ); + const [updateWorkspace] = useUpdateWorkspaceMutation(); + + const aiModels = useRecoilValueV2(aiModelsState); + + const realModels = aiModels.filter( + (model) => !VIRTUAL_MODEL_IDS.has(model.modelId), + ); + + const currentSmartModel = currentWorkspace?.smartModel; + + const defaultModelOptions = realModels + .filter((model) => !model.deprecated || model.modelId === currentSmartModel) + .map((model) => ({ + value: model.modelId, + label: model.label, + Icon: PROVIDER_CONFIG[model.provider.toUpperCase()]?.Icon, + })); + + const handleDefaultModelChange = async (value: string) => { + if (!currentWorkspace?.id) { + return; + } + + const previousSmartModel = currentWorkspace.smartModel; + + try { + setCurrentWorkspace({ + ...currentWorkspace, + smartModel: value, + }); + + await updateWorkspace({ + variables: { + input: { + smartModel: value, + }, + }, + }); + + enqueueSuccessSnackBar({ + message: t`Default model updated successfully`, + }); + } catch { + setCurrentWorkspace({ + ...currentWorkspace, + smartModel: previousSmartModel, + }); + + enqueueErrorSnackBar({ + message: t`Failed to update default model`, + }); + } + }; + + return ( +
+ + + + + - - - - - - - -
- - {t`Smart Model`} - - - {t`Advanced model for complex planning`} - -
- -