From c1fd23742f867e9b0ecb20f9da80e63e81b36cd6 Mon Sep 17 00:00:00 2001 From: Phantom Date: Fri, 31 Oct 2025 14:41:07 +0800 Subject: [PATCH] fix: activate assistant/agent when creating new (#11009) * refactor: remove unused SWITCH_ASSISTANT event and related code Clean up unused event and associated listener in HomePage component * feat(agents): improve agent handling and state management - Return result from useUpdateAgent hook - Update useActiveTopic to handle null assistantId - Add state management for active agent and topic in Tabs - Implement afterSubmit callback in AgentModal - Refactor agent press handling in AssistantsTab - Clean up HomePage state management logic - Add afterCreate callback in UnifiedAddButton * refactor(agent): update agent and session update functions to return entities Modify update functions in useUpdateAgent and useUpdateSession hooks to return updated entities. Update related components to handle the new return types and adjust type definitions accordingly. * refactor(hooks): simplify active topic hook by using useAssistant * refactor(agent): consolidate agent update types and functions Move UpdateAgentBaseOptions and related function types from hooks/agents/types.ts to types/agent.ts Update components to use new UpdateAgentFunctionUnion type Simplify component props by removing redundant type definitions * refactor(agent): update type for plugin settings update function * refactor(AgentSettings): simplify tooling settings type definitions Remove unused hooks and use direct type imports instead of ReturnType --- .../components/Popups/agent/AgentModal.tsx | 18 +++++-- src/renderer/src/hooks/agents/types.ts | 4 -- .../src/hooks/agents/useUpdateAgent.ts | 10 ++-- .../src/hooks/agents/useUpdateSession.ts | 10 ++-- src/renderer/src/hooks/useTopic.ts | 4 +- src/renderer/src/pages/home/HomePage.tsx | 51 ++++--------------- .../src/pages/home/Tabs/AssistantsTab.tsx | 34 +++++++++++-- .../home/Tabs/components/UnifiedAddButton.tsx | 37 ++++++++++++-- src/renderer/src/pages/home/Tabs/index.tsx | 11 +++- .../home/components/ChatNavbarContent.tsx | 7 ++- .../AgentSettings/AccessibleDirsSetting.tsx | 8 +-- .../settings/AgentSettings/AvatarSetting.tsx | 10 +++- .../AgentSettings/DescriptionSetting.tsx | 8 +-- .../AgentSettings/EssentialSettings.tsx | 4 +- .../settings/AgentSettings/ModelSetting.tsx | 14 +++-- .../settings/AgentSettings/NameSetting.tsx | 6 +-- .../settings/AgentSettings/PluginSettings.tsx | 4 +- .../AgentSettings/ToolingSettings.tsx | 8 +-- src/renderer/src/services/EventService.ts | 1 - src/renderer/src/types/agent.ts | 19 +++++++ 20 files changed, 175 insertions(+), 93 deletions(-) delete mode 100644 src/renderer/src/hooks/agents/types.ts diff --git a/src/renderer/src/components/Popups/agent/AgentModal.tsx b/src/renderer/src/components/Popups/agent/AgentModal.tsx index 609593493a..d49dbb812b 100644 --- a/src/renderer/src/components/Popups/agent/AgentModal.tsx +++ b/src/renderer/src/components/Popups/agent/AgentModal.tsx @@ -67,6 +67,7 @@ type Props = { agent?: AgentWithTools isOpen: boolean onClose: () => void + afterSubmit?: (a: AgentEntity) => void } /** @@ -78,7 +79,7 @@ type Props = { * @param onClose - Optional callback when modal closes. From useDisclosure. * @returns Modal component for agent creation/editing */ -export const AgentModal: React.FC = ({ agent, isOpen: _isOpen, onClose: _onClose }) => { +export const AgentModal: React.FC = ({ agent, isOpen: _isOpen, onClose: _onClose, afterSubmit }) => { const { isOpen, onClose } = useDisclosure({ isOpen: _isOpen, onClose: _onClose }) const { t } = useTranslation() const loadingRef = useRef(false) @@ -301,8 +302,13 @@ export const AgentModal: React.FC = ({ agent, isOpen: _isOpen, onClose: _ configuration: form.configuration ? { ...form.configuration } : undefined } satisfies UpdateAgentForm - updateAgent(updatePayload) - logger.debug('Updated agent', updatePayload) + const result = await updateAgent(updatePayload) + if (result) { + logger.debug('Updated agent', result) + afterSubmit?.(result) + } else { + logger.error('Update failed.') + } } else { const newAgent = { type: form.type, @@ -315,12 +321,13 @@ export const AgentModal: React.FC = ({ agent, isOpen: _isOpen, onClose: _ configuration: form.configuration ? { ...form.configuration } : undefined } satisfies AddAgentForm const result = await addAgent(newAgent) + if (!result.success) { loadingRef.current = false throw result.error } + afterSubmit?.(result.data) } - loadingRef.current = false // setTimeoutTimer('onCreateAgent', () => EventEmitter.emit(EVENT_NAMES.SHOW_ASSISTANTS), 0) @@ -329,16 +336,17 @@ export const AgentModal: React.FC = ({ agent, isOpen: _isOpen, onClose: _ [ form.type, form.model, + form.accessible_paths, form.name, form.description, form.instructions, - form.accessible_paths, form.allowed_tools, form.configuration, agent, onClose, t, updateAgent, + afterSubmit, addAgent ] ) diff --git a/src/renderer/src/hooks/agents/types.ts b/src/renderer/src/hooks/agents/types.ts deleted file mode 100644 index 9cf5769f57..0000000000 --- a/src/renderer/src/hooks/agents/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type UpdateAgentBaseOptions = { - /** Whether to show success toast after updating. Defaults to true. */ - showSuccessToast?: boolean -} diff --git a/src/renderer/src/hooks/agents/useUpdateAgent.ts b/src/renderer/src/hooks/agents/useUpdateAgent.ts index db3825b9bb..76d3fbd9ec 100644 --- a/src/renderer/src/hooks/agents/useUpdateAgent.ts +++ b/src/renderer/src/hooks/agents/useUpdateAgent.ts @@ -1,10 +1,10 @@ -import { ListAgentsResponse, UpdateAgentForm } from '@renderer/types' +import { AgentEntity, ListAgentsResponse, UpdateAgentForm } from '@renderer/types' +import { UpdateAgentBaseOptions, UpdateAgentFunction } from '@renderer/types/agent' import { formatErrorMessageWithPrefix } from '@renderer/utils/error' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { mutate } from 'swr' -import { UpdateAgentBaseOptions } from './types' import { useAgentClient } from './useAgentClient' export const useUpdateAgent = () => { @@ -12,8 +12,8 @@ export const useUpdateAgent = () => { const client = useAgentClient() const listKey = client.agentPaths.base - const updateAgent = useCallback( - async (form: UpdateAgentForm, options?: UpdateAgentBaseOptions) => { + const updateAgent: UpdateAgentFunction = useCallback( + async (form: UpdateAgentForm, options?: UpdateAgentBaseOptions): Promise => { try { const itemKey = client.agentPaths.withId(form.id) // may change to optimistic update @@ -23,8 +23,10 @@ export const useUpdateAgent = () => { if (options?.showSuccessToast ?? true) { window.toast.success(t('common.update_success')) } + return result } catch (error) { window.toast.error(formatErrorMessageWithPrefix(error, t('agent.update.error.failed'))) + return undefined } }, [client, listKey, t] diff --git a/src/renderer/src/hooks/agents/useUpdateSession.ts b/src/renderer/src/hooks/agents/useUpdateSession.ts index cf52a64630..44a5839d7e 100644 --- a/src/renderer/src/hooks/agents/useUpdateSession.ts +++ b/src/renderer/src/hooks/agents/useUpdateSession.ts @@ -1,18 +1,18 @@ -import { ListAgentSessionsResponse, UpdateSessionForm } from '@renderer/types' +import { AgentSessionEntity, ListAgentSessionsResponse, UpdateSessionForm } from '@renderer/types' +import { UpdateAgentBaseOptions, UpdateAgentSessionFunction } from '@renderer/types/agent' import { getErrorMessage } from '@renderer/utils/error' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { mutate } from 'swr' -import { UpdateAgentBaseOptions } from './types' import { useAgentClient } from './useAgentClient' export const useUpdateSession = (agentId: string | null) => { const { t } = useTranslation() const client = useAgentClient() - const updateSession = useCallback( - async (form: UpdateSessionForm, options?: UpdateAgentBaseOptions) => { + const updateSession: UpdateAgentSessionFunction = useCallback( + async (form: UpdateSessionForm, options?: UpdateAgentBaseOptions): Promise => { if (!agentId) return const paths = client.getSessionPaths(agentId) const listKey = paths.base @@ -29,8 +29,10 @@ export const useUpdateSession = (agentId: string | null) => { if (options?.showSuccessToast ?? true) { window.toast.success(t('common.update_success')) } + return result } catch (error) { window.toast.error({ title: t('agent.session.update.error.failed'), description: getErrorMessage(error) }) + return undefined } }, [agentId, client, t] diff --git a/src/renderer/src/hooks/useTopic.ts b/src/renderer/src/hooks/useTopic.ts index 990cb12db8..b8a3dc977c 100644 --- a/src/renderer/src/hooks/useTopic.ts +++ b/src/renderer/src/hooks/useTopic.ts @@ -10,13 +10,13 @@ import { loadTopicMessagesThunk } from '@renderer/store/thunk/messageThunk' import { Assistant, Topic } from '@renderer/types' import { findMainTextBlocks } from '@renderer/utils/messageUtils/find' import { find, isEmpty } from 'lodash' -import { useEffect, useState } from 'react' +import { type Dispatch, type SetStateAction, useEffect, useState } from 'react' import { useAssistant } from './useAssistant' import { getStoreSetting } from './useSettings' let _activeTopic: Topic -let _setActiveTopic: (topic: Topic) => void +let _setActiveTopic: Dispatch> // const logger = loggerService.withContext('useTopic') diff --git a/src/renderer/src/pages/home/HomePage.tsx b/src/renderer/src/pages/home/HomePage.tsx index d387af12ba..3825630ba1 100644 --- a/src/renderer/src/pages/home/HomePage.tsx +++ b/src/renderer/src/pages/home/HomePage.tsx @@ -4,7 +4,6 @@ import { useAssistants } from '@renderer/hooks/useAssistant' import { useRuntime } from '@renderer/hooks/useRuntime' import { useNavbarPosition, useSettings } from '@renderer/hooks/useSettings' import { useActiveTopic } from '@renderer/hooks/useTopic' -import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import NavigationService from '@renderer/services/NavigationService' import { newMessagesActions } from '@renderer/store/newMessage' import { setActiveAgentId, setActiveTopicOrSessionAction } from '@renderer/store/runtime' @@ -33,8 +32,10 @@ const HomePage: FC = () => { const location = useLocation() const state = location.state - const [activeAssistant, _setActiveAssistant] = useState(state?.assistant || _activeAssistant || assistants[0]) - const { activeTopic, setActiveTopic: _setActiveTopic } = useActiveTopic(activeAssistant?.id, state?.topic) + const [activeAssistant, _setActiveAssistant] = useState( + state?.assistant || _activeAssistant || assistants[0] + ) + const { activeTopic, setActiveTopic: _setActiveTopic } = useActiveTopic(activeAssistant?.id ?? '', state?.topic) const { showAssistants, showTopics, topicPosition } = useSettings() const dispatch = useDispatch() const { chat } = useRuntime() @@ -43,16 +44,20 @@ const HomePage: FC = () => { _activeAssistant = activeAssistant const setActiveAssistant = useCallback( + // TODO: allow to set it as null. (newAssistant: Assistant) => { - if (newAssistant.id === activeAssistant.id) return + if (newAssistant.id === activeAssistant?.id) return startTransition(() => { _setActiveAssistant(newAssistant) + if (newAssistant.id !== 'fake') { + dispatch(setActiveAgentId(null)) + } // 同步更新 active topic,避免不必要的重新渲染 const newTopic = newAssistant.topics[0] _setActiveTopic((prev) => (newTopic?.id === prev.id ? prev : newTopic)) }) }, - [_setActiveTopic, activeAssistant] + [_setActiveTopic, activeAssistant?.id, dispatch] ) const setActiveTopic = useCallback( @@ -76,19 +81,6 @@ const HomePage: FC = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [state]) - useEffect(() => { - const unsubscribe = EventEmitter.on(EVENT_NAMES.SWITCH_ASSISTANT, (assistantId: string) => { - const newAssistant = assistants.find((a) => a.id === assistantId) - if (newAssistant) { - setActiveAssistant(newAssistant) - } - }) - - return () => { - unsubscribe() - } - }, [assistants, setActiveAssistant]) - useEffect(() => { const canMinimize = topicPosition == 'left' ? !showAssistants : !showAssistants && !showTopics window.api.window.setMinimumSize(canMinimize ? SECOND_MIN_WINDOW_WIDTH : MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) @@ -98,29 +90,6 @@ const HomePage: FC = () => { } }, [showAssistants, showTopics, topicPosition]) - useEffect(() => { - if (activeTopicOrSession === 'session') { - setActiveAssistant({ - id: 'fake', - name: '', - prompt: '', - topics: [ - { - id: 'fake', - assistantId: 'fake', - name: 'fake', - createdAt: '', - updatedAt: '', - messages: [] - } as unknown as Topic - ], - type: 'chat' - }) - } else if (activeTopicOrSession === 'topic') { - dispatch(setActiveAgentId(null)) - } - }, [activeTopicOrSession, dispatch, setActiveAssistant]) - return ( {isLeftNavbar && ( diff --git a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx index 8fc439b7b5..2cb6aabfa4 100644 --- a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx @@ -9,7 +9,7 @@ import { useAssistantsTabSortType } from '@renderer/hooks/useStore' import { useTags } from '@renderer/hooks/useTags' import { useAppDispatch } from '@renderer/store' import { addIknowAction } from '@renderer/store/runtime' -import { Assistant, AssistantsSortType } from '@renderer/types' +import { Assistant, AssistantsSortType, Topic } from '@renderer/types' import { getErrorMessage } from '@renderer/utils' import { FC, useCallback, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -99,6 +99,30 @@ const AssistantsTab: FC = (props) => { [setAssistantsTabSortType] ) + const handleAgentPress = useCallback( + (agentId: string) => { + setActiveAgentId(agentId) + // TODO: should allow it to be null + setActiveAssistant({ + id: 'fake', + name: '', + prompt: '', + topics: [ + { + id: 'fake', + assistantId: 'fake', + name: 'fake', + createdAt: '', + updatedAt: '', + messages: [] + } as unknown as Topic + ], + type: 'chat' + }) + }, + [setActiveAgentId, setActiveAssistant] + ) + return ( {!apiServerConfig.enabled && !apiServerRunning && !iknow[ALERT_KEY] && ( @@ -126,7 +150,11 @@ const AssistantsTab: FC = (props) => { /> )} - + {assistantsTabSortType === 'tags' ? ( = (props) => { onAssistantSwitch={setActiveAssistant} onAssistantDelete={onDeleteAssistant} onAgentDelete={deleteAgent} - onAgentPress={setActiveAgentId} + onAgentPress={handleAgentPress} addPreset={addAssistantPreset} copyAssistant={copyAssistant} onCreateDefaultAssistant={onCreateDefaultAssistant} diff --git a/src/renderer/src/pages/home/Tabs/components/UnifiedAddButton.tsx b/src/renderer/src/pages/home/Tabs/components/UnifiedAddButton.tsx index d3e64871a6..d50add0bd8 100644 --- a/src/renderer/src/pages/home/Tabs/components/UnifiedAddButton.tsx +++ b/src/renderer/src/pages/home/Tabs/components/UnifiedAddButton.tsx @@ -1,19 +1,25 @@ import { Button, Popover, PopoverContent, PopoverTrigger, useDisclosure } from '@heroui/react' import { AgentModal } from '@renderer/components/Popups/agent/AgentModal' +import { useAppDispatch } from '@renderer/store' +import { setActiveTopicOrSessionAction } from '@renderer/store/runtime' +import { AgentEntity, Assistant, Topic } from '@renderer/types' import { Bot, MessageSquare } from 'lucide-react' -import { FC, useState } from 'react' +import { FC, useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import AddButton from './AddButton' interface UnifiedAddButtonProps { onCreateAssistant: () => void + setActiveAssistant: (a: Assistant) => void + setActiveAgentId: (id: string) => void } -const UnifiedAddButton: FC = ({ onCreateAssistant }) => { +const UnifiedAddButton: FC = ({ onCreateAssistant, setActiveAssistant, setActiveAgentId }) => { const { t } = useTranslation() const [isPopoverOpen, setIsPopoverOpen] = useState(false) const { isOpen: isAgentModalOpen, onOpen: onAgentModalOpen, onClose: onAgentModalClose } = useDisclosure() + const dispatch = useAppDispatch() const handleAddAssistant = () => { setIsPopoverOpen(false) @@ -25,6 +31,31 @@ const UnifiedAddButton: FC = ({ onCreateAssistant }) => { onAgentModalOpen() } + const afterCreate = useCallback( + (a: AgentEntity) => { + // TODO: should allow it to be null + setActiveAssistant({ + id: 'fake', + name: '', + prompt: '', + topics: [ + { + id: 'fake', + assistantId: 'fake', + name: 'fake', + createdAt: '', + updatedAt: '', + messages: [] + } as unknown as Topic + ], + type: 'chat' + }) + setActiveAgentId(a.id) + dispatch(setActiveTopicOrSessionAction('session')) + }, + [dispatch, setActiveAgentId, setActiveAssistant] + ) + return (
= ({ onCreateAssistant }) => { - +
) } diff --git a/src/renderer/src/pages/home/Tabs/index.tsx b/src/renderer/src/pages/home/Tabs/index.tsx index 775a045d95..4914ae1340 100644 --- a/src/renderer/src/pages/home/Tabs/index.tsx +++ b/src/renderer/src/pages/home/Tabs/index.tsx @@ -7,6 +7,8 @@ import { useRuntime } from '@renderer/hooks/useRuntime' import { useNavbarPosition, useSettings } from '@renderer/hooks/useSettings' import { useShowTopics } from '@renderer/hooks/useStore' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' +import { useAppDispatch } from '@renderer/store' +import { setActiveAgentId, setActiveTopicOrSessionAction } from '@renderer/store/runtime' import { Assistant, Topic } from '@renderer/types' import { Tab } from '@renderer/types/chat' import { classNames, getErrorMessage, uuid } from '@renderer/utils' @@ -50,6 +52,7 @@ const HomeTabs: FC = ({ const { activeTopicOrSession, activeAgentId } = chat const { session, isLoading: isSessionLoading, error: sessionError } = useActiveSession() const { updateSession } = useUpdateSession(activeAgentId) + const dispatch = useAppDispatch() const isSessionView = activeTopicOrSession === 'session' const isTopicView = activeTopicOrSession === 'topic' @@ -69,13 +72,19 @@ const HomeTabs: FC = ({ const onCreateAssistant = async () => { const assistant = await AddAssistantPopup.show() - assistant && setActiveAssistant(assistant) + if (assistant) { + setActiveAssistant(assistant) + dispatch(setActiveAgentId(null)) + dispatch(setActiveTopicOrSessionAction('topic')) + } } const onCreateDefaultAssistant = () => { const assistant = { ...defaultAssistant, id: uuid() } addAssistant(assistant) setActiveAssistant(assistant) + dispatch(setActiveAgentId(null)) + dispatch(setActiveTopicOrSessionAction('topic')) } useEffect(() => { diff --git a/src/renderer/src/pages/home/components/ChatNavbarContent.tsx b/src/renderer/src/pages/home/components/ChatNavbarContent.tsx index 00b48cf8f4..8f0f2b1197 100644 --- a/src/renderer/src/pages/home/components/ChatNavbarContent.tsx +++ b/src/renderer/src/pages/home/components/ChatNavbarContent.tsx @@ -62,7 +62,12 @@ const ChatNavbarContent: FC = ({ assistant }) => { )} {activeSession && ( - + { + await handleUpdateModel(model) + }} + /> )} {activeAgent && activeSession && ( diff --git a/src/renderer/src/pages/settings/AgentSettings/AccessibleDirsSetting.tsx b/src/renderer/src/pages/settings/AgentSettings/AccessibleDirsSetting.tsx index ad228d227c..fcdaee2319 100644 --- a/src/renderer/src/pages/settings/AgentSettings/AccessibleDirsSetting.tsx +++ b/src/renderer/src/pages/settings/AgentSettings/AccessibleDirsSetting.tsx @@ -1,20 +1,20 @@ import { Button, Tooltip } from '@heroui/react' import { loggerService } from '@logger' -import { AgentBaseWithId, UpdateAgentBaseForm } from '@renderer/types' +import { AgentBaseWithId, UpdateAgentBaseForm, UpdateAgentFunctionUnion } from '@renderer/types' import { Plus } from 'lucide-react' -import React, { useCallback } from 'react' +import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { SettingsItem, SettingsTitle } from './shared' export interface AccessibleDirsSettingProps { base: AgentBaseWithId | undefined | null - update: (form: UpdateAgentBaseForm) => Promise + update: UpdateAgentFunctionUnion } const logger = loggerService.withContext('AccessibleDirsSetting') -export const AccessibleDirsSetting: React.FC = ({ base, update }) => { +export const AccessibleDirsSetting = ({ base, update }: AccessibleDirsSettingProps) => { const { t } = useTranslation() const updateAccessiblePaths = useCallback( diff --git a/src/renderer/src/pages/settings/AgentSettings/AvatarSetting.tsx b/src/renderer/src/pages/settings/AgentSettings/AvatarSetting.tsx index f067e6e0ad..af0c92e723 100644 --- a/src/renderer/src/pages/settings/AgentSettings/AvatarSetting.tsx +++ b/src/renderer/src/pages/settings/AgentSettings/AvatarSetting.tsx @@ -1,5 +1,11 @@ import { EmojiAvatarWithPicker } from '@renderer/components/Avatar/EmojiAvatarWithPicker' -import { AgentConfigurationSchema, AgentEntity, isAgentType, UpdateAgentForm } from '@renderer/types' +import { + AgentConfigurationSchema, + AgentEntity, + isAgentType, + UpdateAgentForm, + UpdateAgentFunction +} from '@renderer/types' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -7,7 +13,7 @@ import { SettingsItem, SettingsTitle } from './shared' export interface AvatarSettingsProps { agent: AgentEntity - update: (form: UpdateAgentForm) => Promise + update: UpdateAgentFunction } // const logger = loggerService.withContext('AvatarSetting') diff --git a/src/renderer/src/pages/settings/AgentSettings/DescriptionSetting.tsx b/src/renderer/src/pages/settings/AgentSettings/DescriptionSetting.tsx index 5400e8e437..4adeff9d0f 100644 --- a/src/renderer/src/pages/settings/AgentSettings/DescriptionSetting.tsx +++ b/src/renderer/src/pages/settings/AgentSettings/DescriptionSetting.tsx @@ -1,16 +1,16 @@ import { Textarea } from '@heroui/react' -import { AgentBaseWithId, UpdateAgentBaseForm } from '@renderer/types' -import React, { useCallback, useState } from 'react' +import { AgentBaseWithId, UpdateAgentBaseForm, UpdateAgentFunctionUnion } from '@renderer/types' +import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { SettingsItem, SettingsTitle } from './shared' export interface DescriptionSettingProps { base: AgentBaseWithId | undefined | null - update: (form: UpdateAgentBaseForm) => Promise + update: UpdateAgentFunctionUnion } -export const DescriptionSetting: React.FC = ({ base, update }) => { +export const DescriptionSetting = ({ base, update }: DescriptionSettingProps) => { const { t } = useTranslation() const [description, setDescription] = useState(base?.description?.trim()) diff --git a/src/renderer/src/pages/settings/AgentSettings/EssentialSettings.tsx b/src/renderer/src/pages/settings/AgentSettings/EssentialSettings.tsx index c374893fcf..c21dca7689 100644 --- a/src/renderer/src/pages/settings/AgentSettings/EssentialSettings.tsx +++ b/src/renderer/src/pages/settings/AgentSettings/EssentialSettings.tsx @@ -46,7 +46,9 @@ const EssentialSettings: FC = ({ agentBase, update, show )} - {isAgent && } + {isAgent && ( + ['updateAgent']} /> + )} {showModelSetting && } diff --git a/src/renderer/src/pages/settings/AgentSettings/ModelSetting.tsx b/src/renderer/src/pages/settings/AgentSettings/ModelSetting.tsx index aed615b860..6662b22e76 100644 --- a/src/renderer/src/pages/settings/AgentSettings/ModelSetting.tsx +++ b/src/renderer/src/pages/settings/AgentSettings/ModelSetting.tsx @@ -1,16 +1,16 @@ import SelectAgentBaseModelButton from '@renderer/pages/home/components/SelectAgentBaseModelButton' -import { AgentBaseWithId, ApiModel, UpdateAgentBaseForm } from '@renderer/types' +import { AgentBaseWithId, ApiModel, UpdateAgentFunctionUnion } from '@renderer/types' import { useTranslation } from 'react-i18next' import { SettingsItem, SettingsTitle } from './shared' export interface ModelSettingProps { base: AgentBaseWithId | undefined | null - update: (form: UpdateAgentBaseForm) => Promise + update: UpdateAgentFunctionUnion isDisabled?: boolean } -export const ModelSetting: React.FC = ({ base, update, isDisabled }) => { +export const ModelSetting = ({ base, update, isDisabled }: ModelSettingProps) => { const { t } = useTranslation() const updateModel = async (model: ApiModel) => { @@ -23,7 +23,13 @@ export const ModelSetting: React.FC = ({ base, update, isDisa return ( {t('common.model')} - + { + await updateModel(model) + }} + isDisabled={isDisabled} + /> ) } diff --git a/src/renderer/src/pages/settings/AgentSettings/NameSetting.tsx b/src/renderer/src/pages/settings/AgentSettings/NameSetting.tsx index 26346bc9ae..0cdc3e28b4 100644 --- a/src/renderer/src/pages/settings/AgentSettings/NameSetting.tsx +++ b/src/renderer/src/pages/settings/AgentSettings/NameSetting.tsx @@ -1,5 +1,5 @@ import { Input } from '@heroui/react' -import { AgentBaseWithId, UpdateAgentBaseForm } from '@renderer/types' +import { AgentBaseWithId, UpdateAgentBaseForm, UpdateAgentFunctionUnion } from '@renderer/types' import { useState } from 'react' import { useTranslation } from 'react-i18next' @@ -7,10 +7,10 @@ import { SettingsItem, SettingsTitle } from './shared' export interface NameSettingsProps { base: AgentBaseWithId | undefined | null - update: (form: UpdateAgentBaseForm) => Promise + update: UpdateAgentFunctionUnion } -export const NameSetting: React.FC = ({ base, update }) => { +export const NameSetting = ({ base, update }: NameSettingsProps) => { const { t } = useTranslation() const [name, setName] = useState(base?.name?.trim()) const updateName = async (name: UpdateAgentBaseForm['name']) => { diff --git a/src/renderer/src/pages/settings/AgentSettings/PluginSettings.tsx b/src/renderer/src/pages/settings/AgentSettings/PluginSettings.tsx index 3b54c15e12..aa7bb93ea4 100644 --- a/src/renderer/src/pages/settings/AgentSettings/PluginSettings.tsx +++ b/src/renderer/src/pages/settings/AgentSettings/PluginSettings.tsx @@ -1,6 +1,6 @@ import { Card, CardBody, Tab, Tabs } from '@heroui/react' import { useAvailablePlugins, useInstalledPlugins, usePluginActions } from '@renderer/hooks/usePlugins' -import { GetAgentResponse, GetAgentSessionResponse, UpdateAgentBaseForm } from '@renderer/types/agent' +import { GetAgentResponse, GetAgentSessionResponse, UpdateAgentFunctionUnion } from '@renderer/types/agent' import { FC, useCallback } from 'react' import { useTranslation } from 'react-i18next' @@ -10,7 +10,7 @@ import { SettingsContainer } from './shared' interface PluginSettingsProps { agentBase: GetAgentResponse | GetAgentSessionResponse - update: (partial: UpdateAgentBaseForm) => Promise + update: UpdateAgentFunctionUnion } const PluginSettings: FC = ({ agentBase }) => { diff --git a/src/renderer/src/pages/settings/AgentSettings/ToolingSettings.tsx b/src/renderer/src/pages/settings/AgentSettings/ToolingSettings.tsx index 45782bf43d..f58fae7b6c 100644 --- a/src/renderer/src/pages/settings/AgentSettings/ToolingSettings.tsx +++ b/src/renderer/src/pages/settings/AgentSettings/ToolingSettings.tsx @@ -10,8 +10,8 @@ import { PermissionMode, Tool, UpdateAgentBaseForm, - UpdateAgentForm, - UpdateSessionForm + UpdateAgentFunction, + UpdateAgentSessionFunction } from '@renderer/types' import { Modal } from 'antd' import { ShieldAlert, ShieldCheck, Wrench } from 'lucide-react' @@ -23,11 +23,11 @@ import { SettingsContainer, SettingsItem, SettingsTitle } from './shared' type AgentToolingSettingsProps = | { agentBase: GetAgentResponse | undefined | null - update: (form: UpdateAgentForm) => Promise | void + update: UpdateAgentFunction } | { agentBase: GetAgentSessionResponse | undefined | null - update: (form: UpdateSessionForm) => Promise | void + update: UpdateAgentSessionFunction } type AgentConfigurationState = AgentConfiguration & Record diff --git a/src/renderer/src/services/EventService.ts b/src/renderer/src/services/EventService.ts index ce5895fc36..badaaccf07 100644 --- a/src/renderer/src/services/EventService.ts +++ b/src/renderer/src/services/EventService.ts @@ -18,7 +18,6 @@ export const EVENT_NAMES = { SHOW_CHAT_SETTINGS: 'SHOW_CHAT_SETTINGS', SHOW_TOPIC_SIDEBAR: 'SHOW_TOPIC_SIDEBAR', SWITCH_TOPIC_SIDEBAR: 'SWITCH_TOPIC_SIDEBAR', - SWITCH_ASSISTANT: 'SWITCH_ASSISTANT', NEW_CONTEXT: 'NEW_CONTEXT', NEW_BRANCH: 'NEW_BRANCH', COPY_TOPIC_IMAGE: 'COPY_TOPIC_IMAGE', diff --git a/src/renderer/src/types/agent.ts b/src/renderer/src/types/agent.ts index 478d8fb7a3..cc04dc3f74 100644 --- a/src/renderer/src/types/agent.ts +++ b/src/renderer/src/types/agent.ts @@ -227,6 +227,25 @@ export type SessionForm = CreateSessionForm | UpdateSessionForm export type UpdateAgentBaseForm = Partial & { id: string } +// --------------------- Components & Hooks ---------------------- + +export type UpdateAgentBaseOptions = { + /** Whether to show success toast after updating. Defaults to true. */ + showSuccessToast?: boolean +} + +export type UpdateAgentFunction = ( + form: UpdateAgentForm, + options?: UpdateAgentBaseOptions +) => Promise + +export type UpdateAgentSessionFunction = ( + form: UpdateSessionForm, + options?: UpdateAgentBaseOptions +) => Promise + +export type UpdateAgentFunctionUnion = UpdateAgentFunction | UpdateAgentSessionFunction + // ------------------ API data transfer objects ------------------ export interface CreateAgentRequest extends AgentBase { type: AgentType