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 609593493..d49dbb812 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 9cf5769f5..000000000 --- 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 db3825b9b..76d3fbd9e 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 cf52a6463..44a5839d7 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 990cb12db..b8a3dc977 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 d387af12b..3825630ba 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 8fc439b7b..2cb6aabfa 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 d3e64871a..d50add0bd 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 775a045d9..4914ae134 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 00b48cf8f..8f0f2b119 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 ad228d227..fcdaee231 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 f067e6e0a..af0c92e72 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 5400e8e43..4adeff9d0 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 c374893fc..c21dca768 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 aed615b86..6662b22e7 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 26346bc9a..0cdc3e28b 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 3b54c15e1..aa7bb93ea 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 45782bf43..f58fae7b6 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 ce5895fc3..badaaccf0 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 478d8fb7a..cc04dc3f7 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