diff --git a/src/renderer/src/Router.tsx b/src/renderer/src/Router.tsx index 505b81dcb8..9fc87e9181 100644 --- a/src/renderer/src/Router.tsx +++ b/src/renderer/src/Router.tsx @@ -8,7 +8,7 @@ import { ErrorBoundary } from './components/ErrorBoundary' import TabsContainer from './components/Tab/TabContainer' import NavigationHandler from './handler/NavigationHandler' import { useNavbarPosition } from './hooks/useSettings' -import AgentsPage from './pages/agents/AgentsPage' +import AssistantPresetsPage from './pages/assistantPresets/AssistantPresetsPage' import CodeToolsPage from './pages/code/CodeToolsPage' import FilesPage from './pages/files/FilesPage' import HomePage from './pages/home/HomePage' @@ -29,7 +29,7 @@ const Router: FC = () => { } /> - } /> + } /> } /> } /> } /> diff --git a/src/renderer/src/components/Popups/AddAssistantPopup.tsx b/src/renderer/src/components/Popups/AddAssistantPopup.tsx index 75759232ee..0a14a47d89 100644 --- a/src/renderer/src/components/Popups/AddAssistantPopup.tsx +++ b/src/renderer/src/components/Popups/AddAssistantPopup.tsx @@ -1,8 +1,8 @@ import { TopView } from '@renderer/components/TopView' -import { useAgents } from '@renderer/hooks/useAgents' import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant' +import { useAssistantPresets } from '@renderer/hooks/useAssistantPresets' import { useTimer } from '@renderer/hooks/useTimer' -import { useSystemAgents } from '@renderer/pages/agents' +import { useSystemAssistantPresets } from '@renderer/pages/assistantPresets' import { createAssistantFromAgent } from '@renderer/services/AssistantService' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import { Assistant, AssistantPreset } from '@renderer/types' @@ -25,25 +25,25 @@ interface Props { const PopupContainer: React.FC = ({ resolve }) => { const [open, setOpen] = useState(true) const { t } = useTranslation() - const { agents: userAgents } = useAgents() + const { presets: userPresets } = useAssistantPresets() const [searchText, setSearchText] = useState('') const { defaultAssistant } = useDefaultAssistant() const { assistants, addAssistant } = useAssistants() const inputRef = useRef(null) - const systemAgents = useSystemAgents() + const systemPresets = useSystemAssistantPresets() const loadingRef = useRef(false) const [selectedIndex, setSelectedIndex] = useState(0) const containerRef = useRef(null) const { setTimeoutTimer } = useTimer() - const agents = useMemo(() => { - const allAgents = [...userAgents, ...systemAgents] as AssistantPreset[] - const list = [defaultAssistant, ...allAgents.filter((agent) => !assistants.map((a) => a.id).includes(agent.id))] + const presets = useMemo(() => { + const allPresets = [...userPresets, ...systemPresets] as AssistantPreset[] + const list = [defaultAssistant, ...allPresets.filter((preset) => !assistants.map((a) => a.id).includes(preset.id))] const filtered = searchText ? list.filter( - (agent) => - agent.name.toLowerCase().includes(searchText.trim().toLocaleLowerCase()) || - agent.description?.toLowerCase().includes(searchText.trim().toLocaleLowerCase()) + (preset) => + preset.name.toLowerCase().includes(searchText.trim().toLocaleLowerCase()) || + preset.description?.toLowerCase().includes(searchText.trim().toLocaleLowerCase()) ) : list @@ -59,15 +59,15 @@ const PopupContainer: React.FC = ({ resolve }) => { return [newAgent, ...filtered] } return filtered - }, [assistants, defaultAssistant, searchText, systemAgents, userAgents]) + }, [assistants, defaultAssistant, searchText, systemPresets, userPresets]) // 重置选中索引当搜索或列表内容变更时 useEffect(() => { setSelectedIndex(0) - }, [agents.length, searchText]) + }, [presets.length, searchText]) const onCreateAssistant = useCallback( - async (agent: AssistantPreset) => { + async (preset: AssistantPreset) => { if (loadingRef.current) { return } @@ -75,11 +75,11 @@ const PopupContainer: React.FC = ({ resolve }) => { loadingRef.current = true let assistant: Assistant - if (agent.id === 'default') { - assistant = { ...agent, id: uuid() } + if (preset.id === 'default') { + assistant = { ...preset, id: uuid() } addAssistant(assistant) } else { - assistant = await createAssistantFromAgent(agent) + assistant = await createAssistantFromAgent(preset) } setTimeoutTimer('onCreateAssistant', () => EventEmitter.emit(EVENT_NAMES.SHOW_ASSISTANTS), 0) @@ -93,28 +93,28 @@ const PopupContainer: React.FC = ({ resolve }) => { if (!open) return const handleKeyDown = (e: KeyboardEvent) => { - const displayedAgents = take(agents, 100) + const displayedPresets = take(presets, 100) switch (e.key) { case 'ArrowDown': e.preventDefault() - setSelectedIndex((prev) => (prev >= displayedAgents.length - 1 ? 0 : prev + 1)) + setSelectedIndex((prev) => (prev >= displayedPresets.length - 1 ? 0 : prev + 1)) break case 'ArrowUp': e.preventDefault() - setSelectedIndex((prev) => (prev <= 0 ? displayedAgents.length - 1 : prev - 1)) + setSelectedIndex((prev) => (prev <= 0 ? displayedPresets.length - 1 : prev - 1)) break case 'Enter': case 'NumpadEnter': // 如果焦点在输入框且有搜索内容,则默认选择第一项 if (document.activeElement === inputRef.current?.input && searchText.trim()) { e.preventDefault() - onCreateAssistant(displayedAgents[selectedIndex]) + onCreateAssistant(displayedPresets[selectedIndex]) } // 否则选择当前选中项 - else if (selectedIndex >= 0 && selectedIndex < displayedAgents.length) { + else if (selectedIndex >= 0 && selectedIndex < displayedPresets.length) { e.preventDefault() - onCreateAssistant(displayedAgents[selectedIndex]) + onCreateAssistant(displayedPresets[selectedIndex]) } break } @@ -122,14 +122,14 @@ const PopupContainer: React.FC = ({ resolve }) => { window.addEventListener('keydown', handleKeyDown) return () => window.removeEventListener('keydown', handleKeyDown) - }, [open, selectedIndex, agents, searchText, onCreateAssistant]) + }, [open, selectedIndex, presets, searchText, onCreateAssistant]) // 确保选中项在可视区域 useEffect(() => { if (containerRef.current) { - const agentItems = containerRef.current.querySelectorAll('.agent-item') - if (agentItems[selectedIndex]) { - agentItems[selectedIndex].scrollIntoView({ + const presetItems = containerRef.current.querySelectorAll('.agent-item') + if (presetItems[selectedIndex]) { + presetItems[selectedIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' }) @@ -193,19 +193,19 @@ const PopupContainer: React.FC = ({ resolve }) => { - {take(agents, 100).map((agent, index) => ( + {take(presets, 100).map((preset, index) => ( onCreateAssistant(agent)} - className={`agent-item ${agent.id === 'default' ? 'default' : ''} ${index === selectedIndex ? 'keyboard-selected' : ''}`} + key={preset.id} + onClick={() => onCreateAssistant(preset)} + className={`agent-item ${preset.id === 'default' ? 'default' : ''} ${index === selectedIndex ? 'keyboard-selected' : ''}`} onMouseEnter={() => setSelectedIndex(index)}> - - {agent.name} + + {preset.name} - {agent.id === 'default' && {t('agents.tag.system')}} - {agent.type === 'agent' && {t('agents.tag.agent')}} - {agent.id === 'new' && {t('agents.tag.new')}} + {preset.id === 'default' && {t('agents.tag.system')}} + {preset.type === 'agent' && {t('agents.tag.agent')}} + {preset.id === 'new' && {t('agents.tag.new')}} ))} diff --git a/src/renderer/src/hooks/useAgents.ts b/src/renderer/src/hooks/useAgents.ts deleted file mode 100644 index b739146bd2..0000000000 --- a/src/renderer/src/hooks/useAgents.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useAppDispatch, useAppSelector } from '@renderer/store' -import { - addAssistantPreset, - removeAssistantPreset, - setAssistantPresets, - updateAssistantPreset, - updateAssistantPresetSettings -} from '@renderer/store/agents' -import { AssistantPreset, AssistantSettings } from '@renderer/types' - -export function useAgents() { - const agents = useAppSelector((state) => state.agents.agents) - const dispatch = useAppDispatch() - - return { - agents, - setAgents: (agents: AssistantPreset[]) => dispatch(setAssistantPresets(agents)), - addAgent: (agent: AssistantPreset) => dispatch(addAssistantPreset(agent)), - removeAgent: (id: string) => dispatch(removeAssistantPreset({ id })) - } -} - -export function useAgent(id: string) { - const agent = useAppSelector((state) => state.agents.agents.find((a) => a.id === id) as AssistantPreset) - const dispatch = useAppDispatch() - - return { - agent, - updateAgent: (agent: AssistantPreset) => dispatch(updateAssistantPreset(agent)), - updateAgentSettings: (settings: Partial) => { - dispatch(updateAssistantPresetSettings({ assistantId: agent.id, settings })) - } - } -} diff --git a/src/renderer/src/hooks/useAssistantPresets.ts b/src/renderer/src/hooks/useAssistantPresets.ts new file mode 100644 index 0000000000..488d400462 --- /dev/null +++ b/src/renderer/src/hooks/useAssistantPresets.ts @@ -0,0 +1,35 @@ +import { useAppDispatch, useAppSelector } from '@renderer/store' +import { + addAssistantPreset, + removeAssistantPreset, + setAssistantPresets, + updateAssistantPreset, + updateAssistantPresetSettings +} from '@renderer/store/agents' +import { AssistantPreset, AssistantSettings } from '@renderer/types' + +export function useAssistantPresets() { + const presets = useAppSelector((state) => state.agents.agents) + const dispatch = useAppDispatch() + + return { + presets, + setAssistantPresets: (presets: AssistantPreset[]) => dispatch(setAssistantPresets(presets)), + addAssistantPreset: (preset: AssistantPreset) => dispatch(addAssistantPreset(preset)), + removeAssistantPreset: (id: string) => dispatch(removeAssistantPreset({ id })) + } +} + +export function useAssistantPreset(id: string) { + // FIXME: undefined is not handled + const preset = useAppSelector((state) => state.agents.agents.find((a) => a.id === id) as AssistantPreset) + const dispatch = useAppDispatch() + + return { + preset, + updateAssistantPreset: (preset: AssistantPreset) => dispatch(updateAssistantPreset(preset)), + updateAssistantPresetSettings: (settings: Partial) => { + dispatch(updateAssistantPresetSettings({ assistantId: preset.id, settings })) + } + } +} diff --git a/src/renderer/src/hooks/useKnowledge.ts b/src/renderer/src/hooks/useKnowledge.ts index 05e77dd8a9..5f5addac81 100644 --- a/src/renderer/src/hooks/useKnowledge.ts +++ b/src/renderer/src/hooks/useKnowledge.ts @@ -33,8 +33,8 @@ import { cloneDeep } from 'lodash' import { useCallback, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' -import { useAgents } from './useAgents' import { useAssistants } from './useAssistant' +import { useAssistantPresets } from './useAssistantPresets' import { useTimer } from './useTimer' export const useKnowledge = (baseId: string) => { @@ -352,7 +352,7 @@ export const useKnowledgeBases = () => { const dispatch = useDispatch() const bases = useSelector((state: RootState) => state.knowledge.bases) const { assistants, updateAssistants } = useAssistants() - const { agents, setAgents } = useAgents() + const { presets, setAssistantPresets } = useAssistantPresets() const addKnowledgeBase = (base: KnowledgeBase) => { dispatch(addBase(base)) @@ -379,7 +379,7 @@ export const useKnowledgeBases = () => { }) // remove agent knowledge_base - const _agents = agents.map((agent) => { + const _presets = presets.map((agent) => { if (agent.knowledge_bases?.find((kb) => kb.id === baseId)) { return { ...agent, @@ -390,7 +390,7 @@ export const useKnowledgeBases = () => { }) updateAssistants(_assistants) - setAgents(_agents) + setAssistantPresets(_presets) } const updateKnowledgeBases = (bases: KnowledgeBase[]) => { diff --git a/src/renderer/src/pages/agents/AgentsPage.tsx b/src/renderer/src/pages/assistantPresets/AssistantPresetsPage.tsx similarity index 82% rename from src/renderer/src/pages/agents/AgentsPage.tsx rename to src/renderer/src/pages/assistantPresets/AssistantPresetsPage.tsx index 7fed6089d2..fa2f6caa35 100644 --- a/src/renderer/src/pages/agents/AgentsPage.tsx +++ b/src/renderer/src/pages/assistantPresets/AssistantPresetsPage.tsx @@ -4,7 +4,7 @@ import { HStack } from '@renderer/components/Layout' import ListItem from '@renderer/components/ListItem' import Scrollbar from '@renderer/components/Scrollbar' import CustomTag from '@renderer/components/Tags/CustomTag' -import { useAgents } from '@renderer/hooks/useAgents' +import { useAssistantPresets } from '@renderer/hooks/useAssistantPresets' import { useNavbarPosition } from '@renderer/hooks/useSettings' import { createAssistantFromAgent } from '@renderer/services/AssistantService' import { AssistantPreset } from '@renderer/types' @@ -17,65 +17,65 @@ import { useTranslation } from 'react-i18next' import ReactMarkdown from 'react-markdown' import styled from 'styled-components' -import { groupByCategories, useSystemAgents } from '.' -import { groupTranslations } from './agentGroupTranslations' -import AddAgentPopup from './components/AddAgentPopup' -import AgentCard from './components/AgentCard' -import { AgentGroupIcon } from './components/AgentGroupIcon' -import ImportAgentPopup from './components/ImportAgentPopup' +import { groupByCategories, useSystemAssistantPresets } from '.' +import { groupTranslations } from './assistantPresetGroupTranslations' +import AddAssistantPresetPopup from './components/AddAssistantPresetPopup' +import AssistantPresetCard from './components/AssistantPresetCard' +import { AssistantPresetGroupIcon } from './components/AssistantPresetGroupIcon' +import ImportAssistantPresetPopup from './components/ImportAssistantPresetPopup' -const AgentsPage: FC = () => { +const AssistantPresetsPage: FC = () => { const [search, setSearch] = useState('') const [searchInput, setSearchInput] = useState('') const [activeGroup, setActiveGroup] = useState('我的') const [agentGroups, setAgentGroups] = useState>({}) const [isSearchExpanded, setIsSearchExpanded] = useState(false) - const systemAgents = useSystemAgents() - const { agents: userAgents } = useAgents() + const systemPresets = useSystemAssistantPresets() + const { presets: userPresets } = useAssistantPresets() const { isTopNavbar } = useNavbarPosition() useEffect(() => { - const systemAgentsGroupList = groupByCategories(systemAgents) + const systemAgentsGroupList = groupByCategories(systemPresets) const agentsGroupList = { - 我的: userAgents, + 我的: userPresets, 精选: [], ...systemAgentsGroupList } as Record setAgentGroups(agentsGroupList) - }, [systemAgents, userAgents]) + }, [systemPresets, userPresets]) - const filteredAgents = useMemo(() => { + const filteredPresets = useMemo(() => { // 搜索框为空直接返回「我的」分组下的 agent if (!search.trim()) { return agentGroups[activeGroup] || [] } - const uniqueAgents = new Map() + const uniquePresets = new Map() Object.entries(agentGroups).forEach(([, agents]) => { agents.forEach((agent) => { if ( agent.name.toLowerCase().includes(search.toLowerCase()) || agent.description?.toLowerCase().includes(search.toLowerCase()) ) { - uniqueAgents.set(agent.id, agent) + uniquePresets.set(agent.id, agent) } }) }) - return Array.from(uniqueAgents.values()) + return Array.from(uniquePresets.values()) }, [agentGroups, activeGroup, search]) const { t, i18n } = useTranslation() - const onAddAgentConfirm = useCallback( - (agent: AssistantPreset) => { + const onAddPresetConfirm = useCallback( + (preset: AssistantPreset) => { window.modal.confirm({ - title: agent.name, + title: preset.name, content: ( - {agent.description && {agent.description}} + {preset.description && {preset.description}} - {agent.prompt && ( + {preset.prompt && ( - {agent.prompt} + {preset.prompt} )} @@ -87,16 +87,16 @@ const AgentsPage: FC = () => { centered: true, okButtonProps: { type: 'primary' }, okText: t('agents.add.button'), - onOk: () => createAssistantFromAgent(agent) + onOk: () => createAssistantFromAgent(preset) }) }, [t] ) - const getAgentFromSystemAgent = useCallback((agent: (typeof systemAgents)[number]) => { + const getPresetFromSystemPreset = useCallback((preset: (typeof systemPresets)[number]) => { return { - ...omit(agent, 'group'), - name: agent.name, + ...omit(preset, 'group'), + name: preset.name, id: uuid(), topics: [], type: 'agent' @@ -161,14 +161,14 @@ const AgentsPage: FC = () => { } const handleAddAgent = () => { - AddAgentPopup.show().then(() => { + AddAssistantPresetPopup.show().then(() => { handleSearchClear() }) } const handleImportAgent = async () => { try { - await ImportAgentPopup.show() + await ImportAssistantPresetPopup.show() } catch (error) { window.toast.error(error instanceof Error ? error.message : t('message.agents.import.error')) } @@ -207,7 +207,7 @@ const AgentsPage: FC = () => { title={ - + {getLocalizedGroupName(group)} { @@ -229,19 +229,19 @@ const AgentsPage: FC = () => { {search.trim() ? ( <> - + {search.trim()}{' '} ) : ( <> - + {getLocalizedGroupName(activeGroup)} )} { - {filteredAgents.length} + {filteredPresets.length} } @@ -282,13 +282,13 @@ const AgentsPage: FC = () => { - {filteredAgents.length > 0 ? ( + {filteredPresets.length > 0 ? ( - {filteredAgents.map((agent, index) => ( - ( + onAddAgentConfirm(getAgentFromSystemAgent(agent))} - agent={agent} + onClick={() => onAddPresetConfirm(getPresetFromSystemPreset(agent))} + preset={agent} activegroup={activeGroup} getLocalizedGroupName={getLocalizedGroupName} /> @@ -390,4 +390,4 @@ const EmptyView = styled.div` color: var(--color-text-secondary); ` -export default AgentsPage +export default AssistantPresetsPage diff --git a/src/renderer/src/pages/agents/agentGroupTranslations.ts b/src/renderer/src/pages/assistantPresets/assistantPresetGroupTranslations.ts similarity index 99% rename from src/renderer/src/pages/agents/agentGroupTranslations.ts rename to src/renderer/src/pages/assistantPresets/assistantPresetGroupTranslations.ts index 201afc876c..082d1796b8 100644 --- a/src/renderer/src/pages/agents/agentGroupTranslations.ts +++ b/src/renderer/src/pages/assistantPresets/assistantPresetGroupTranslations.ts @@ -1,3 +1,4 @@ +// FIXME: Just use i18next! export type GroupTranslations = { [key: string]: { 'el-GR': string diff --git a/src/renderer/src/pages/agents/components/AddAgentPopup.tsx b/src/renderer/src/pages/assistantPresets/components/AddAssistantPresetPopup.tsx similarity index 96% rename from src/renderer/src/pages/agents/components/AddAgentPopup.tsx rename to src/renderer/src/pages/assistantPresets/components/AddAssistantPresetPopup.tsx index 8919fa66e5..dc90f755df 100644 --- a/src/renderer/src/pages/agents/components/AddAgentPopup.tsx +++ b/src/renderer/src/pages/assistantPresets/components/AddAssistantPresetPopup.tsx @@ -5,7 +5,7 @@ import { loggerService } from '@logger' import EmojiPicker from '@renderer/components/EmojiPicker' import { TopView } from '@renderer/components/TopView' import { AGENT_PROMPT } from '@renderer/config/prompts' -import { useAgents } from '@renderer/hooks/useAgents' +import { useAssistantPresets } from '@renderer/hooks/useAssistantPresets' import { useSidebarIconShow } from '@renderer/hooks/useSidebarIcon' import { fetchGenerate } from '@renderer/services/ApiService' import { getDefaultModel } from '@renderer/services/AssistantService' @@ -31,13 +31,13 @@ type FieldType = { knowledge_base_ids: string[] } -const logger = loggerService.withContext('AddAgentPopup') +const logger = loggerService.withContext('AddAssistantPresetPopup') const PopupContainer: React.FC = ({ resolve }) => { const [open, setOpen] = useState(true) const [form] = Form.useForm() const { t } = useTranslation() - const { addAgent } = useAgents() + const { addAssistantPreset } = useAssistantPresets() const formRef = useRef(null) const [emoji, setEmoji] = useState('') const [loading, setLoading] = useState(false) @@ -91,7 +91,7 @@ const PopupContainer: React.FC = ({ resolve }) => { messages: [] } - addAgent(_agent) + addAssistantPreset(_agent) resolve(_agent) setOpen(false) } @@ -266,10 +266,10 @@ const TokenCount = styled.div` user-select: none; ` -export default class AddAgentPopup { +export default class AddAssistantPresetPopup { static topviewId = 0 static hide() { - TopView.hide('AddAgentPopup') + TopView.hide('AddAssistantPresetPopup') } static show() { return new Promise((resolve) => { @@ -280,7 +280,7 @@ export default class AddAgentPopup { this.hide() }} />, - 'AddAgentPopup' + 'AddAssistantPresetPopup' ) }) } diff --git a/src/renderer/src/pages/agents/components/AgentCard.tsx b/src/renderer/src/pages/assistantPresets/components/AssistantPresetCard.tsx similarity index 84% rename from src/renderer/src/pages/agents/components/AgentCard.tsx rename to src/renderer/src/pages/assistantPresets/components/AssistantPresetCard.tsx index 56ecebfc97..a288334ba6 100644 --- a/src/renderer/src/pages/agents/components/AgentCard.tsx +++ b/src/renderer/src/pages/assistantPresets/components/AssistantPresetCard.tsx @@ -1,6 +1,6 @@ import { DeleteIcon, EditIcon } from '@renderer/components/Icons' import CustomTag from '@renderer/components/Tags/CustomTag' -import { useAgents } from '@renderer/hooks/useAgents' +import { useAssistantPresets } from '@renderer/hooks/useAssistantPresets' import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings' import { createAssistantFromAgent } from '@renderer/services/AssistantService' import type { AssistantPreset } from '@renderer/types' @@ -11,50 +11,50 @@ import { ArrowDownAZ, Ellipsis, PlusIcon, SquareArrowOutUpRight } from 'lucide-r import { type FC, memo, useCallback, useEffect, useRef, useState } from 'react' import styled from 'styled-components' -import ManageAgentsPopup from './ManageAgentsPopup' +import ManageAssistantPresetsPopup from './ManageAssistantPresetsPopup' interface Props { - agent: AssistantPreset + preset: AssistantPreset activegroup?: string onClick: () => void getLocalizedGroupName: (group: string) => string } -const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupName }) => { - const { removeAgent } = useAgents() +const AssistantPresetCard: FC = ({ preset, onClick, activegroup, getLocalizedGroupName }) => { + const { removeAssistantPreset } = useAssistantPresets() const [isVisible, setIsVisible] = useState(false) const cardRef = useRef(null) const handleDelete = useCallback( - (agent: AssistantPreset) => { + (preset: AssistantPreset) => { window.modal.confirm({ centered: true, content: t('agents.delete.popup.content'), - onOk: () => removeAgent(agent.id) + onOk: () => removeAssistantPreset(preset.id) }) }, - [removeAgent] + [removeAssistantPreset] ) - const exportAgent = useCallback(async () => { + const exportPreset = useCallback(async () => { const result = [ { - name: agent.name, - emoji: agent.emoji, - group: agent.group, - prompt: agent.prompt, - description: agent.description, - regularPhrases: agent.regularPhrases, + name: preset.name, + emoji: preset.emoji, + group: preset.group, + prompt: preset.prompt, + description: preset.description, + regularPhrases: preset.regularPhrases, type: 'agent' } ] const resultStr = JSON.stringify(result, null, 2) - await window.api.file.save(`${agent.name}.json`, new TextEncoder().encode(resultStr), { + await window.api.file.save(`${preset.name}.json`, new TextEncoder().encode(resultStr), { filters: [{ name: t('agents.import.file_filter'), extensions: ['json'] }] }) - }, [agent]) + }, [preset]) const menuItems = [ { @@ -63,7 +63,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa icon: , onClick: (e: any) => { e.domEvent.stopPropagation() - AssistantSettingsPopup.show({ assistant: agent }) + AssistantSettingsPopup.show({ assistant: preset }) } }, { @@ -72,7 +72,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa icon: , onClick: (e: any) => { e.domEvent.stopPropagation() - createAssistantFromAgent(agent) + createAssistantFromAgent(preset) } }, { @@ -81,7 +81,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa icon: , onClick: (e: any) => { e.domEvent.stopPropagation() - ManageAgentsPopup.show() + ManageAssistantPresetsPopup.show() } }, { @@ -90,7 +90,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa icon: , onClick: (e: any) => { e.domEvent.stopPropagation() - exportAgent() + exportPreset() } }, { @@ -100,7 +100,7 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa danger: true, onClick: (e: any) => { e.domEvent.stopPropagation() - handleDelete(agent) + handleDelete(preset) } } ] @@ -125,8 +125,8 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa } }, []) - const emoji = agent.emoji || getLeadingEmoji(agent.name) - const prompt = (agent.description || agent.prompt).substring(0, 200).replace(/\\n/g, '') + const emoji = preset.emoji || getLeadingEmoji(preset.name) + const prompt = (preset.description || preset.prompt).substring(0, 200).replace(/\\n/g, '') const content = ( @@ -135,15 +135,15 @@ const AgentCard: FC = ({ agent, onClick, activegroup, getLocalizedGroupNa {emoji} - {agent.name} + {preset.name} {activegroup === '我的' && ( {getLocalizedGroupName('我的')} )} - {!!agent.group?.length && - agent.group.map((group) => ( + {!!preset.group?.length && + preset.group.map((group) => ( {getLocalizedGroupName(group)} @@ -346,4 +346,4 @@ const AgentPrompt = styled.div` color: var(--color-text-2); ` -export default memo(AgentCard) +export default memo(AssistantPresetCard) diff --git a/src/renderer/src/pages/agents/components/AgentGroupIcon.tsx b/src/renderer/src/pages/assistantPresets/components/AssistantPresetGroupIcon.tsx similarity index 89% rename from src/renderer/src/pages/agents/components/AgentGroupIcon.tsx rename to src/renderer/src/pages/assistantPresets/components/AssistantPresetGroupIcon.tsx index 2e08ff3cd4..3d31ffe887 100644 --- a/src/renderer/src/pages/agents/components/AgentGroupIcon.tsx +++ b/src/renderer/src/pages/assistantPresets/components/AssistantPresetGroupIcon.tsx @@ -1,4 +1,4 @@ -import { groupTranslations } from '@renderer/pages/agents/agentGroupTranslations' +import { groupTranslations } from '@renderer/pages/assistantPresets/assistantPresetGroupTranslations' import { DynamicIcon, IconName } from 'lucide-react/dynamic' import { FC } from 'react' import { useTranslation } from 'react-i18next' @@ -9,7 +9,7 @@ interface Props { strokeWidth?: number } -export const AgentGroupIcon: FC = ({ groupName, size = 20, strokeWidth = 1.2 }) => { +export const AssistantPresetGroupIcon: FC = ({ groupName, size = 20, strokeWidth = 1.2 }) => { const { i18n } = useTranslation() const currentLanguage = i18n.language as keyof (typeof groupTranslations)[string] diff --git a/src/renderer/src/pages/agents/components/ImportAgentPopup.tsx b/src/renderer/src/pages/assistantPresets/components/ImportAssistantPresetPopup.tsx similarity index 80% rename from src/renderer/src/pages/agents/components/ImportAgentPopup.tsx rename to src/renderer/src/pages/assistantPresets/components/ImportAssistantPresetPopup.tsx index 25b0e69df3..f850feb576 100644 --- a/src/renderer/src/pages/agents/components/ImportAgentPopup.tsx +++ b/src/renderer/src/pages/assistantPresets/components/ImportAssistantPresetPopup.tsx @@ -1,5 +1,5 @@ import { TopView } from '@renderer/components/TopView' -import { useAgents } from '@renderer/hooks/useAgents' +import { useAssistantPresets } from '@renderer/hooks/useAssistantPresets' import { useTimer } from '@renderer/hooks/useTimer' import { getDefaultModel } from '@renderer/services/AssistantService' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' @@ -17,7 +17,7 @@ const PopupContainer: React.FC = ({ resolve }) => { const [open, setOpen] = useState(true) const [form] = Form.useForm() const { t } = useTranslation() - const { addAgent } = useAgents() + const { addAssistantPreset } = useAssistantPresets() const [importType, setImportType] = useState<'url' | 'file'>('url') const [loading, setLoading] = useState(false) const { setTimeoutTimer } = useTimer() @@ -25,7 +25,7 @@ const PopupContainer: React.FC = ({ resolve }) => { const onFinish = async (values: { url?: string }) => { setLoading(true) try { - let agents: AssistantPreset[] = [] + let presets: AssistantPreset[] = [] if (importType === 'url') { if (!values.url) { @@ -36,16 +36,16 @@ const PopupContainer: React.FC = ({ resolve }) => { throw new Error(t('agents.import.error.fetch_failed')) } const data = await response.json() - agents = Array.isArray(data) ? data : [data] + presets = Array.isArray(data) ? data : [data] } else { const result = await window.api.file.open({ filters: [{ name: t('agents.import.file_filter'), extensions: ['json'] }] }) if (result) { - agents = JSON.parse(new TextDecoder('utf-8').decode(result.content)) - if (!Array.isArray(agents)) { - agents = [agents] + presets = JSON.parse(new TextDecoder('utf-8').decode(result.content)) + if (!Array.isArray(presets)) { + presets = [presets] } } else { return @@ -53,32 +53,32 @@ const PopupContainer: React.FC = ({ resolve }) => { } // Validate and process agents - for (const agent of agents) { - if (!agent.name || !agent.prompt) { + for (const preset of presets) { + if (!preset.name || !preset.prompt) { throw new Error(t('agents.import.error.invalid_format')) } - const newAgent: AssistantPreset = { + const newPreset: AssistantPreset = { id: uuid(), - name: agent.name, - emoji: agent.emoji || '🤖', - group: agent.group || [], - prompt: agent.prompt, - description: agent.description || '', + name: preset.name, + emoji: preset.emoji || '🤖', + group: preset.group || [], + prompt: preset.prompt, + description: preset.description || '', type: 'agent', topics: [], messages: [], defaultModel: getDefaultModel(), - regularPhrases: agent.regularPhrases || [] + regularPhrases: preset.regularPhrases || [] } - addAgent(newAgent) + addAssistantPreset(newPreset) } window.toast.success(t('message.agents.imported')) setTimeoutTimer('onFinish', () => EventEmitter.emit(EVENT_NAMES.SHOW_ASSISTANTS), 0) setOpen(false) - resolve(agents) + resolve(presets) } catch (error) { window.toast.error(error instanceof Error ? error.message : t('message.agents.import.error')) } finally { @@ -131,7 +131,7 @@ const PopupContainer: React.FC = ({ resolve }) => { ) } -export default class ImportAgentPopup { +export default class ImportAssistantPresetPopup { static show() { return new Promise((resolve) => { TopView.show( @@ -141,12 +141,12 @@ export default class ImportAgentPopup { this.hide() }} />, - 'ImportAgentPopup' + 'ImportAssistantPresetPopup' ) }) } static hide() { - TopView.hide('ImportAgentPopup') + TopView.hide('ImportAssistantPresetPopup') } } diff --git a/src/renderer/src/pages/agents/components/ManageAgentsPopup.tsx b/src/renderer/src/pages/assistantPresets/components/ManageAssistantPresetsPopup.tsx similarity index 77% rename from src/renderer/src/pages/agents/components/ManageAgentsPopup.tsx rename to src/renderer/src/pages/assistantPresets/components/ManageAssistantPresetsPopup.tsx index a56432fb23..bab91668a4 100644 --- a/src/renderer/src/pages/agents/components/ManageAgentsPopup.tsx +++ b/src/renderer/src/pages/assistantPresets/components/ManageAssistantPresetsPopup.tsx @@ -2,7 +2,7 @@ import { MenuOutlined } from '@ant-design/icons' import { DraggableList } from '@renderer/components/DraggableList' import { Box, HStack } from '@renderer/components/Layout' import { TopView } from '@renderer/components/TopView' -import { useAgents } from '@renderer/hooks/useAgents' +import { useAssistantPresets } from '@renderer/hooks/useAssistantPresets' import { Empty, Modal } from 'antd' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -11,7 +11,7 @@ import styled from 'styled-components' const PopupContainer: React.FC = () => { const [open, setOpen] = useState(true) const { t } = useTranslation() - const { agents, setAgents } = useAgents() + const { presets, setAssistantPresets } = useAssistantPresets() const onOk = () => { setOpen(false) @@ -22,14 +22,14 @@ const PopupContainer: React.FC = () => { } const onClose = async () => { - ManageAgentsPopup.hide() + ManageAssistantPresetsPopup.hide() } useEffect(() => { - if (agents.length === 0) { + if (presets.length === 0) { setOpen(false) } - }, [agents]) + }, [presets]) return ( { transitionName="animation-move-down" centered> - {agents.length > 0 && ( - + {presets.length > 0 && ( + {(item) => ( @@ -56,7 +56,7 @@ const PopupContainer: React.FC = () => { )} )} - {agents.length === 0 && } + {presets.length === 0 && } ) @@ -90,12 +90,12 @@ const AgentItem = styled.div` } ` -export default class ManageAgentsPopup { +export default class ManageAssistantPresetsPopup { static topviewId = 0 static hide() { - TopView.hide('ManageAgentsPopup') + TopView.hide('ManageAssistantPresetsPopup') } static show() { - TopView.show(, 'ManageAgentsPopup') + TopView.show(, 'ManageAssistantPresetsPopup') } } diff --git a/src/renderer/src/pages/agents/index.ts b/src/renderer/src/pages/assistantPresets/index.ts similarity index 89% rename from src/renderer/src/pages/agents/index.ts rename to src/renderer/src/pages/assistantPresets/index.ts index 2c85f894c6..5dd2604e5c 100644 --- a/src/renderer/src/pages/agents/index.ts +++ b/src/renderer/src/pages/assistantPresets/index.ts @@ -26,9 +26,9 @@ export const getAgentsFromSystemAgents = (systemAgents: any) => { return agents } -export function useSystemAgents() { - const { defaultAgent } = useSettings() - const [agents, setAgents] = useState([]) +export function useSystemAssistantPresets() { + const { defaultAgent: defaultPreset } = useSettings() + const [presets, setPresets] = useState([]) const { resourcesPath } = useRuntime() const { agentssubscribeUrl } = store.getState().settings const { i18n } = useTranslation() @@ -46,7 +46,7 @@ export function useSystemAgents() { throw new Error(`HTTP error! Status: ${response.status}`) } const agentsData = (await response.json()) as AssistantPreset[] - setAgents(agentsData) + setPresets(agentsData) return } catch (error) { logger.error('Failed to load remote agents:', error as Error) @@ -65,18 +65,18 @@ export function useSystemAgents() { } } - setAgents(_agents) + setPresets(_agents) } catch (error) { logger.error('Failed to load agents:', error as Error) // 发生错误时使用已加载的本地 agents - setAgents(_agents) + setPresets(_agents) } } loadAgents() - }, [defaultAgent, resourcesPath, agentssubscribeUrl, currentLanguage]) + }, [defaultPreset, resourcesPath, agentssubscribeUrl, currentLanguage]) - return agents + return presets } export function groupByCategories(data: AssistantPreset[]) { diff --git a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx index 906b14d4e5..8a72ecfd22 100644 --- a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx @@ -1,8 +1,8 @@ import { DownOutlined, RightOutlined } from '@ant-design/icons' import { DraggableList } from '@renderer/components/DraggableList' import Scrollbar from '@renderer/components/Scrollbar' -import { useAgents } from '@renderer/hooks/useAgents' import { useAssistants } from '@renderer/hooks/useAssistant' +import { useAssistantPresets } from '@renderer/hooks/useAssistantPresets' import { useAssistantsTabSortType } from '@renderer/hooks/useStore' import { useTags } from '@renderer/hooks/useTags' import { Assistant, AssistantsSortType } from '@renderer/types' @@ -30,7 +30,7 @@ const Assistants: FC = ({ }) => { const { assistants, removeAssistant, copyAssistant, updateAssistants } = useAssistants() const [dragging, setDragging] = useState(false) - const { addAgent } = useAgents() + const { addAssistantPreset } = useAssistantPresets() const { t } = useTranslation() const { getGroupedAssistants, collapsedTags, toggleTagCollapse } = useTags() const { assistantsTabSortType = 'list', setAssistantsTabSortType } = useAssistantsTabSortType() @@ -134,7 +134,7 @@ const Assistants: FC = ({ sortBy={assistantsTabSortType} onSwitch={setActiveAssistant} onDelete={onDelete} - addAgent={addAgent} + addPreset={addAssistantPreset} copyAssistant={copyAssistant} onCreateDefaultAssistant={onCreateDefaultAssistant} handleSortByChange={handleSortByChange} @@ -167,7 +167,7 @@ const Assistants: FC = ({ sortBy={assistantsTabSortType} onSwitch={setActiveAssistant} onDelete={onDelete} - addAgent={addAgent} + addPreset={addAssistantPreset} copyAssistant={copyAssistant} onCreateDefaultAssistant={onCreateDefaultAssistant} handleSortByChange={handleSortByChange} diff --git a/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx b/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx index d20c69b052..6b4f2a7ce5 100644 --- a/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx +++ b/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx @@ -40,7 +40,7 @@ interface AssistantItemProps { onSwitch: (assistant: Assistant) => void onDelete: (assistant: Assistant) => void onCreateDefaultAssistant: () => void - addAgent: (agent: any) => void + addPreset: (agent: any) => void copyAssistant: (assistant: Assistant) => void onTagClick?: (tag: string) => void handleSortByChange?: (sortType: AssistantsSortType) => void @@ -52,7 +52,7 @@ const AssistantItem: FC = ({ sortBy, onSwitch, onDelete, - addAgent, + addPreset, copyAssistant, handleSortByChange }) => { @@ -91,7 +91,7 @@ const AssistantItem: FC = ({ allTags, assistants, updateAssistants, - addAgent, + addPreset, copyAssistant, onSwitch, onDelete, @@ -108,7 +108,7 @@ const AssistantItem: FC = ({ allTags, assistants, updateAssistants, - addAgent, + addPreset, copyAssistant, onSwitch, onDelete, @@ -249,7 +249,7 @@ function getMenuItems({ allTags, assistants, updateAssistants, - addAgent, + addPreset, copyAssistant, onSwitch, onDelete, @@ -297,10 +297,10 @@ function getMenuItems({ key: 'save-to-agent', icon: , onClick: async () => { - const agent = omit(assistant, ['model', 'emoji']) - agent.id = uuid() - agent.type = 'agent' - addAgent(agent) + const preset = omit(assistant, ['model', 'emoji']) + preset.id = uuid() + preset.type = 'agent' + addPreset(preset) window.toast.success(t('assistants.save.success')) } }, diff --git a/src/renderer/src/pages/settings/AssistantSettings/index.tsx b/src/renderer/src/pages/settings/AssistantSettings/index.tsx index 3b7140512d..042076f837 100644 --- a/src/renderer/src/pages/settings/AssistantSettings/index.tsx +++ b/src/renderer/src/pages/settings/AssistantSettings/index.tsx @@ -1,7 +1,7 @@ import { HStack } from '@renderer/components/Layout' import { TopView } from '@renderer/components/TopView' -import { useAgent } from '@renderer/hooks/useAgents' import { useAssistant } from '@renderer/hooks/useAssistant' +import { useAssistantPreset } from '@renderer/hooks/useAssistantPresets' import { useSidebarIconShow } from '@renderer/hooks/useSidebarIcon' import { Assistant } from '@renderer/types' import { Menu, Modal } from 'antd' @@ -40,12 +40,14 @@ const AssistantSettingPopupContainer: React.FC = ({ resolve, tab, ...prop const [menu, setMenu] = useState(tab || 'prompt') const _useAssistant = useAssistant(props.assistant.id) - const _useAgent = useAgent(props.assistant.id) + const _useAgent = useAssistantPreset(props.assistant.id) const isAgent = props.assistant.type === 'agent' - const assistant = isAgent ? _useAgent.agent : _useAssistant.assistant - const updateAssistant = isAgent ? _useAgent.updateAgent : _useAssistant.updateAssistant - const updateAssistantSettings = isAgent ? _useAgent.updateAgentSettings : _useAssistant.updateAssistantSettings + const assistant = isAgent ? _useAgent.preset : _useAssistant.assistant + const updateAssistant = isAgent ? _useAgent.updateAssistantPreset : _useAssistant.updateAssistant + const updateAssistantSettings = isAgent + ? _useAgent.updateAssistantPresetSettings + : _useAssistant.updateAssistantSettings const showKnowledgeIcon = useSidebarIconShow('knowledge') diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts index 79f2797abd..8b9182c7bc 100644 --- a/src/renderer/src/store/settings.ts +++ b/src/renderer/src/store/settings.ts @@ -156,6 +156,7 @@ export interface SettingsState { joplinUrl: string | null joplinExportReasoning: boolean defaultObsidianVault: string | null + /** This state is actaully default assistant preset */ defaultAgent: string | null // 思源笔记配置 siyuanApiUrl: string | null