添加智能体订阅功能 (#5954)

* 添加智能体订阅功能

* 修改图标

* 修改hook点

修改图标

* 优雅的引用图标

* feat(i18n): add settings title for agents in multiple languages

* fix(i18n): update translations for improved clarity

* Merge branch 'main' into Subscribe

---------

Co-authored-by: VM 96 <eov@88.com>
Co-authored-by: suyao <sy20010504@gmail.com>
This commit is contained in:
上房揭瓦 2025-05-13 23:09:38 +08:00 committed by GitHub
parent 8bd38ccd86
commit 71cd2def2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 105 additions and 9 deletions

View File

@ -44,6 +44,9 @@
"my_agents": "My Agents",
"search.no_results": "No results found",
"sorting.title": "Sorting",
"settings": {
"title": "Agent Setting"
},
"tag.agent": "Agent",
"tag.default": "Default",
"tag.new": "New",

View File

@ -48,7 +48,10 @@
"tag.default": "デフォルト",
"tag.new": "新規",
"tag.system": "システム",
"title": "エージェント"
"title": "エージェント",
"settings": {
"title": "エージェント設定"
}
},
"assistants": {
"title": "アシスタント",

View File

@ -48,6 +48,9 @@
},
"export": {
"agent": "Экспорт агента"
},
"settings": {
"title": "Настройки агента"
}
},
"assistants": {

View File

@ -48,7 +48,10 @@
"tag.default": "默认",
"tag.new": "新建",
"tag.system": "系统",
"title": "智能体"
"title": "智能体",
"settings": {
"title": "智能体配置"
}
},
"assistants": {
"title": "助手",

View File

@ -48,7 +48,10 @@
"tag.default": "預設",
"tag.new": "新增",
"tag.system": "系統",
"title": "智慧代理人"
"title": "智慧代理人",
"settings": {
"title": "智慧代理人設定"
}
},
"assistants": {
"title": "助手",

View File

@ -2,6 +2,8 @@ import { useRuntime } from '@renderer/hooks/useRuntime'
import { useSettings } from '@renderer/hooks/useSettings'
import { Agent } from '@renderer/types'
import { useEffect, useState } from 'react'
import store from '@renderer/store'
let _agents: Agent[] = []
export const getAgentsFromSystemAgents = (systemAgents: any) => {
@ -19,27 +21,44 @@ export function useSystemAgents() {
const { defaultAgent } = useSettings()
const [agents, setAgents] = useState<Agent[]>([])
const { resourcesPath } = useRuntime()
const { agentssubscribeUrl } = store.getState().settings
useEffect(() => {
const loadAgents = async () => {
try {
// 始终加载本地 agents
// 检查是否使用远程数据源
if (agentssubscribeUrl && agentssubscribeUrl.startsWith('http')) {
try {
await new Promise(resolve => setTimeout(resolve, 500));
const response = await fetch(agentssubscribeUrl);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const agentsData = await response.json() as Agent[];
setAgents(agentsData);
return;
} catch (error) {
console.error("Failed to load remote agents:", error);
// 远程加载失败,继续尝试加载本地数据
}
}
// 如果没有远程配置或获取失败,加载本地代理
if (resourcesPath && _agents.length === 0) {
const localAgentsData = await window.api.fs.read(resourcesPath + '/data/agents.json')
_agents = JSON.parse(localAgentsData) as Agent[]
}
// 如果没有远程配置或获取失败,使用本地 agents
setAgents(_agents)
} catch (error) {
console.error('Failed to load agents:', error)
// 发生错误时使用本地 agents
// 发生错误时使用已加载的本地 agents
setAgents(_agents)
}
}
loadAgents()
}, [defaultAgent, resourcesPath])
}, [defaultAgent, resourcesPath, agentssubscribeUrl])
return agents
}

View File

@ -0,0 +1,47 @@
import { HStack } from '@renderer/components/Layout'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import { setAgentssubscribeUrl } from '@renderer/store/settings'
import Input from 'antd/es/input/Input'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle } from '..'
const AgentsSubscribeUrlSettings: FC = () => {
const { t } = useTranslation()
const { theme } = useTheme()
const dispatch = useAppDispatch()
const { agentssubscribeUrl } = useSettings()
const handleAgentChange = (e: React.ChangeEvent<HTMLInputElement>) => {
dispatch(setAgentssubscribeUrl(e.target.value))
}
return (
<SettingGroup theme={theme}>
<SettingTitle>
{t('agents.tag.agent')}
{t('settings.websearch.subscribe_add')}
</SettingTitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.websearch.subscribe_url')}</SettingRowTitle>
<HStack alignItems="center" gap="5px" style={{ width: 315 }}>
<Input
type="text"
value={agentssubscribeUrl || ''}
onChange={handleAgentChange}
style={{ width: 315 }}
placeholder={t('settings.websearch.subscribe_name.placeholder')}
/>
</HStack>
</SettingRow>
<SettingDivider />
</SettingGroup>
)
}
export default AgentsSubscribeUrlSettings

View File

@ -17,12 +17,13 @@ import { reset } from '@renderer/services/BackupService'
import { AppInfo } from '@renderer/types'
import { formatFileSize } from '@renderer/utils'
import { Button, Typography } from 'antd'
import { FileText, FolderCog, FolderInput } from 'lucide-react'
import { FileText, FolderCog, FolderInput, Sparkle } from 'lucide-react'
import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { SettingContainer, SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle } from '..'
import AgentsSubscribeUrlSettings from './AgentsSubscribeUrlSettings'
import ExportMenuOptions from './ExportMenuSettings'
import JoplinSettings from './JoplinSettings'
import MarkdownExportSettings from './MarkdownExportSettings'
@ -81,6 +82,7 @@ const DataSettings: FC = () => {
title: 'settings.data.markdown_export.title',
icon: <FileText size={16} />
},
{ key: 'divider_3', isDivider: true, text: t('settings.data.divider.third_party') },
{ key: 'notion', title: 'settings.data.notion.title', icon: <i className="iconfont icon-notion" /> },
{
@ -102,6 +104,11 @@ const DataSettings: FC = () => {
key: 'siyuan',
title: 'settings.data.siyuan.title',
icon: <SiyuanIcon />
},
{
key: 'agentssubscribe_url',
title: 'agents.settings.title',
icon: <Sparkle size={16} className="icon" />
}
]
@ -253,6 +260,7 @@ const DataSettings: FC = () => {
{menu === 'joplin' && <JoplinSettings />}
{menu === 'obsidian' && <ObsidianSettings />}
{menu === 'siyuan' && <SiyuanSettings />}
{menu === 'agentssubscribe_url' && <AgentsSubscribeUrlSettings />}
</SettingContainer>
</Container>
)

View File

@ -111,6 +111,8 @@ export interface SettingsState {
siyuanToken: string | null
siyuanBoxId: string | null
siyuanRootPath: string | null
// 订阅的助手地址
agentssubscribeUrl: string | null
// MinApps
maxKeepAliveMinapps: number
showOpenedMinappsInSidebar: boolean
@ -218,6 +220,7 @@ export const initialState: SettingsState = {
siyuanToken: null,
siyuanBoxId: null,
siyuanRootPath: null,
agentssubscribeUrl: '',
// MinApps
maxKeepAliveMinapps: 3,
showOpenedMinappsInSidebar: true,
@ -493,6 +496,9 @@ const settingsSlice = createSlice({
setSiyuanRootPath: (state, action: PayloadAction<string>) => {
state.siyuanRootPath = action.payload
},
setAgentssubscribeUrl: (state, action: PayloadAction<string>) => {
state.agentssubscribeUrl = action.payload
},
setMaxKeepAliveMinapps: (state, action: PayloadAction<number>) => {
state.maxKeepAliveMinapps = action.payload
},
@ -599,6 +605,7 @@ export const {
setSiyuanApiUrl,
setSiyuanToken,
setSiyuanBoxId,
setAgentssubscribeUrl,
setSiyuanRootPath,
setMaxKeepAliveMinapps,
setShowOpenedMinappsInSidebar,