mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-08 14:29:15 +08:00
feat: 支持自定义助手地址 (#5540)
* feat: 支持自定义助手地址 feat: 支持自定义助手地址 * feat: 更新多语言支持,添加“defaultaides”字段至隐私设置,并修改默认智能体的值为设置中的引用。 * feat: 更新默认助手设置,修复函数命名错误并优化状态管理 * refactor: update agent loading logic to use settings and improve error handling * refactor: update DefaultaidesSettings to use custom hook for state management and replace icon in DataSettings * fix: improve error message formatting in callMCPTool function * feat: 添加多语言支持的默认助手设置,包括英文、日文、俄文和中文的翻译。 * refactor: 优化智能体加载逻辑,合并本地和远程智能体,并改进错误处理。 * feat: add import functionality for agents and update translations in multiple languages. * feat: implement agent import functionality with validation and error handling. * feat(i18n): add import success and error messages for agents in multiple languages. * fix(i18n): standardize import success message key across multiple languages. * refactor(i18n): remove default aides section from multiple language files * refactor(i18n): update Traditional Chinese translations for agent management and privacy settings. * feat(i18n): add import functionality for agents with URL and file options, including error handling and translations in multiple languages. * refactor(i18n): rename 'defaultaides' to 'defaultAgent' across multiple language files and update related settings. * refactor(AgentsPage): remove unused addAgent function from useAgents hook. --------- Co-authored-by: 上房揭瓦 <hoaobo@foxmail.com> Co-authored-by: George Zhao <georgezhao@SKJLAB> Co-authored-by: suyao <sy20010504@gmail.com>
This commit is contained in:
parent
0bad95230e
commit
1e5ec5df7f
@ -9,6 +9,23 @@
|
|||||||
"add.prompt": "Prompt",
|
"add.prompt": "Prompt",
|
||||||
"add.prompt.placeholder": "Enter prompt",
|
"add.prompt.placeholder": "Enter prompt",
|
||||||
"add.title": "Create Agent",
|
"add.title": "Create Agent",
|
||||||
|
"import.title": "Import from External",
|
||||||
|
"import": {
|
||||||
|
"title": "Import from External",
|
||||||
|
"type": {
|
||||||
|
"url": "URL",
|
||||||
|
"file": "File"
|
||||||
|
},
|
||||||
|
"url_placeholder": "Enter JSON URL",
|
||||||
|
"select_file": "Select File",
|
||||||
|
"button": "Import",
|
||||||
|
"file_filter": "JSON Files",
|
||||||
|
"error": {
|
||||||
|
"url_required": "Please enter a URL",
|
||||||
|
"fetch_failed": "Failed to fetch from URL",
|
||||||
|
"invalid_format": "Invalid agent format: missing required fields"
|
||||||
|
}
|
||||||
|
},
|
||||||
"delete.popup.content": "Are you sure you want to delete this agent?",
|
"delete.popup.content": "Are you sure you want to delete this agent?",
|
||||||
"edit.message.add.title": "Add",
|
"edit.message.add.title": "Add",
|
||||||
"edit.message.assistant.placeholder": "Enter assistant message",
|
"edit.message.assistant.placeholder": "Enter assistant message",
|
||||||
@ -498,6 +515,10 @@
|
|||||||
"title": "Mermaid Diagram"
|
"title": "Mermaid Diagram"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
|
"agents": {
|
||||||
|
"imported": "Imported successfully",
|
||||||
|
"import.error": "Import failed"
|
||||||
|
},
|
||||||
"api.check.model.title": "Select the model to use for detection",
|
"api.check.model.title": "Select the model to use for detection",
|
||||||
"api.connection.failed": "Connection failed",
|
"api.connection.failed": "Connection failed",
|
||||||
"api.connection.success": "Connection successful",
|
"api.connection.success": "Connection successful",
|
||||||
@ -707,7 +728,7 @@
|
|||||||
"aspect_ratio": "Aspect Ratio",
|
"aspect_ratio": "Aspect Ratio",
|
||||||
"style_type": "Style",
|
"style_type": "Style",
|
||||||
"learn_more": "Learn More",
|
"learn_more": "Learn More",
|
||||||
"prompt_placeholder_edit": "Enter your image description, text drawing uses “double quotes” to wrap",
|
"prompt_placeholder_edit": "Enter your image description, text drawing uses \"double quotes\" to wrap",
|
||||||
"proxy_required": "Currently, you need to open a proxy to view the generated images, it will be supported in the future",
|
"proxy_required": "Currently, you need to open a proxy to view the generated images, it will be supported in the future",
|
||||||
"image_file_required": "Please upload an image first",
|
"image_file_required": "Please upload an image first",
|
||||||
"image_file_retry": "Please re-upload an image first",
|
"image_file_retry": "Please re-upload an image first",
|
||||||
@ -1515,7 +1536,8 @@
|
|||||||
"privacy": {
|
"privacy": {
|
||||||
"title": "Privacy Settings",
|
"title": "Privacy Settings",
|
||||||
"enable_privacy_mode": "Anonymous reporting of errors and statistics"
|
"enable_privacy_mode": "Anonymous reporting of errors and statistics"
|
||||||
}
|
},
|
||||||
|
"defaultAgent": "Built-in"
|
||||||
},
|
},
|
||||||
"translate": {
|
"translate": {
|
||||||
"any.language": "Any language",
|
"any.language": "Any language",
|
||||||
|
|||||||
@ -9,6 +9,23 @@
|
|||||||
"add.prompt": "プロンプト",
|
"add.prompt": "プロンプト",
|
||||||
"add.prompt.placeholder": "プロンプトを入力",
|
"add.prompt.placeholder": "プロンプトを入力",
|
||||||
"add.title": "エージェントを作成",
|
"add.title": "エージェントを作成",
|
||||||
|
"import.title": "外部からインポート",
|
||||||
|
"import": {
|
||||||
|
"title": "外部からインポート",
|
||||||
|
"type": {
|
||||||
|
"url": "URL",
|
||||||
|
"file": "ファイル"
|
||||||
|
},
|
||||||
|
"url_placeholder": "JSON URLを入力",
|
||||||
|
"select_file": "ファイルを選択",
|
||||||
|
"button": "インポート",
|
||||||
|
"file_filter": "JSONファイル",
|
||||||
|
"error": {
|
||||||
|
"url_required": "URLを入力してください",
|
||||||
|
"fetch_failed": "URLからのデータ取得に失敗しました",
|
||||||
|
"invalid_format": "無効なエージェント形式:必須フィールドが不足しています"
|
||||||
|
}
|
||||||
|
},
|
||||||
"delete.popup.content": "このエージェントを削除してもよろしいですか?",
|
"delete.popup.content": "このエージェントを削除してもよろしいですか?",
|
||||||
"edit.message.add.title": "追加",
|
"edit.message.add.title": "追加",
|
||||||
"edit.message.assistant.placeholder": "アシスタントのメッセージを入力",
|
"edit.message.assistant.placeholder": "アシスタントのメッセージを入力",
|
||||||
@ -498,6 +515,10 @@
|
|||||||
"title": "Mermaid図"
|
"title": "Mermaid図"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
|
"agents": {
|
||||||
|
"imported": "インポートに成功しました",
|
||||||
|
"import.error": "インポートに失敗しました"
|
||||||
|
},
|
||||||
"api.check.model.title": "検出に使用するモデルを選択してください",
|
"api.check.model.title": "検出に使用するモデルを選択してください",
|
||||||
"api.connection.failed": "接続に失敗しました",
|
"api.connection.failed": "接続に失敗しました",
|
||||||
"api.connection.success": "接続に成功しました",
|
"api.connection.success": "接続に成功しました",
|
||||||
@ -1515,6 +1536,7 @@
|
|||||||
"title": "プライバシー設定",
|
"title": "プライバシー設定",
|
||||||
"enable_privacy_mode": "匿名エラーレポートとデータ統計の送信"
|
"enable_privacy_mode": "匿名エラーレポートとデータ統計の送信"
|
||||||
},
|
},
|
||||||
|
"defaultAgent": "内蔵",
|
||||||
"input.show_translate_confirm": "翻訳確認ダイアログを表示"
|
"input.show_translate_confirm": "翻訳確認ダイアログを表示"
|
||||||
},
|
},
|
||||||
"translate": {
|
"translate": {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"translation": {
|
"translation": {
|
||||||
"agents": {
|
"agents": {
|
||||||
"add.button": "Добавить к ассистенту",
|
"add.button": "Добавить в ассистента",
|
||||||
"add.knowledge_base": "База знаний",
|
"add.knowledge_base": "База знаний",
|
||||||
"add.knowledge_base.placeholder": "Выберите базу знаний",
|
"add.knowledge_base.placeholder": "Выберите базу знаний",
|
||||||
"add.name": "Имя",
|
"add.name": "Имя",
|
||||||
@ -9,6 +9,7 @@
|
|||||||
"add.prompt": "Промпт",
|
"add.prompt": "Промпт",
|
||||||
"add.prompt.placeholder": "Введите промпт",
|
"add.prompt.placeholder": "Введите промпт",
|
||||||
"add.title": "Создать агента",
|
"add.title": "Создать агента",
|
||||||
|
"import.title": "Импорт из внешнего источника",
|
||||||
"delete.popup.content": "Вы уверены, что хотите удалить этого агента?",
|
"delete.popup.content": "Вы уверены, что хотите удалить этого агента?",
|
||||||
"edit.message.add.title": "Добавить",
|
"edit.message.add.title": "Добавить",
|
||||||
"edit.message.assistant.placeholder": "Введите сообщение ассистента",
|
"edit.message.assistant.placeholder": "Введите сообщение ассистента",
|
||||||
@ -29,7 +30,23 @@
|
|||||||
"tag.default": "По умолчанию",
|
"tag.default": "По умолчанию",
|
||||||
"tag.new": "Новый",
|
"tag.new": "Новый",
|
||||||
"tag.system": "Система",
|
"tag.system": "Система",
|
||||||
"title": "Агенты"
|
"title": "Агенты",
|
||||||
|
"import": {
|
||||||
|
"title": "Импорт из внешнего источника",
|
||||||
|
"type": {
|
||||||
|
"url": "URL",
|
||||||
|
"file": "Файл"
|
||||||
|
},
|
||||||
|
"url_placeholder": "Введите URL JSON",
|
||||||
|
"select_file": "Выбрать файл",
|
||||||
|
"button": "Импорт",
|
||||||
|
"file_filter": "JSON файлы",
|
||||||
|
"error": {
|
||||||
|
"url_required": "Пожалуйста, введите URL",
|
||||||
|
"fetch_failed": "Не удалось получить данные по URL",
|
||||||
|
"invalid_format": "Неверный формат агента: отсутствуют обязательные поля"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"assistants": {
|
"assistants": {
|
||||||
"title": "Ассистенты",
|
"title": "Ассистенты",
|
||||||
@ -498,6 +515,10 @@
|
|||||||
"title": "Диаграмма Mermaid"
|
"title": "Диаграмма Mermaid"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
|
"agents": {
|
||||||
|
"imported": "Импорт успешно выполнен",
|
||||||
|
"import.error": "Импорт не выполнен"
|
||||||
|
},
|
||||||
"api.check.model.title": "Выберите модель для проверки",
|
"api.check.model.title": "Выберите модель для проверки",
|
||||||
"api.connection.failed": "Соединение не удалось",
|
"api.connection.failed": "Соединение не удалось",
|
||||||
"api.connection.success": "Соединение успешно",
|
"api.connection.success": "Соединение успешно",
|
||||||
@ -1512,9 +1533,10 @@
|
|||||||
"multiple": "Множественный выбор"
|
"multiple": "Множественный выбор"
|
||||||
},
|
},
|
||||||
"privacy": {
|
"privacy": {
|
||||||
"title": "Настройки приватности",
|
"title": "Настройки конфиденциальности",
|
||||||
"enable_privacy_mode": "Анонимная отправка отчетов об ошибках и статистики"
|
"enable_privacy_mode": "Анонимная отчетность об ошибках и статистике"
|
||||||
},
|
},
|
||||||
|
"defaultAgent": "Встроенный",
|
||||||
"input.show_translate_confirm": "Показать диалоговое окно подтверждения перевода"
|
"input.show_translate_confirm": "Показать диалоговое окно подтверждения перевода"
|
||||||
},
|
},
|
||||||
"translate": {
|
"translate": {
|
||||||
|
|||||||
@ -9,6 +9,22 @@
|
|||||||
"add.prompt": "提示词",
|
"add.prompt": "提示词",
|
||||||
"add.prompt.placeholder": "输入提示词",
|
"add.prompt.placeholder": "输入提示词",
|
||||||
"add.title": "创建智能体",
|
"add.title": "创建智能体",
|
||||||
|
"import": {
|
||||||
|
"title": "从外部导入",
|
||||||
|
"type": {
|
||||||
|
"url": "URL",
|
||||||
|
"file": "文件"
|
||||||
|
},
|
||||||
|
"url_placeholder": "输入 JSON URL",
|
||||||
|
"select_file": "选择文件",
|
||||||
|
"button": "导入",
|
||||||
|
"file_filter": "JSON 文件",
|
||||||
|
"error": {
|
||||||
|
"url_required": "请输入 URL",
|
||||||
|
"fetch_failed": "从 URL 获取数据失败",
|
||||||
|
"invalid_format": "无效的代理格式:缺少必填字段"
|
||||||
|
}
|
||||||
|
},
|
||||||
"delete.popup.content": "确定要删除此智能体吗?",
|
"delete.popup.content": "确定要删除此智能体吗?",
|
||||||
"edit.message.add.title": "添加",
|
"edit.message.add.title": "添加",
|
||||||
"edit.message.assistant.placeholder": "输入助手消息",
|
"edit.message.assistant.placeholder": "输入助手消息",
|
||||||
@ -498,6 +514,10 @@
|
|||||||
"title": "Mermaid 图表"
|
"title": "Mermaid 图表"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
|
"agents": {
|
||||||
|
"imported": "导入成功",
|
||||||
|
"import.error": "导入失败"
|
||||||
|
},
|
||||||
"api.check.model.title": "请选择要检测的模型",
|
"api.check.model.title": "请选择要检测的模型",
|
||||||
"api.connection.failed": "连接失败",
|
"api.connection.failed": "连接失败",
|
||||||
"api.connection.success": "连接成功",
|
"api.connection.success": "连接成功",
|
||||||
@ -707,7 +727,7 @@
|
|||||||
"aspect_ratio": "画幅比例",
|
"aspect_ratio": "画幅比例",
|
||||||
"style_type": "风格",
|
"style_type": "风格",
|
||||||
"learn_more": "了解更多",
|
"learn_more": "了解更多",
|
||||||
"prompt_placeholder_edit": "输入你的图片描述,文本绘制用 “双引号” 包裹",
|
"prompt_placeholder_edit": "输入你的图片描述,文本绘制用 \"双引号\" 包裹",
|
||||||
"proxy_required": "目前需要打开代理才能查看生成图片,后续会支持国内直连",
|
"proxy_required": "目前需要打开代理才能查看生成图片,后续会支持国内直连",
|
||||||
"image_file_required": "请先上传图片",
|
"image_file_required": "请先上传图片",
|
||||||
"image_file_retry": "请重新上传图片",
|
"image_file_retry": "请重新上传图片",
|
||||||
|
|||||||
@ -9,6 +9,22 @@
|
|||||||
"add.prompt": "提示詞",
|
"add.prompt": "提示詞",
|
||||||
"add.prompt.placeholder": "輸入提示詞",
|
"add.prompt.placeholder": "輸入提示詞",
|
||||||
"add.title": "建立智慧代理人",
|
"add.title": "建立智慧代理人",
|
||||||
|
"import": {
|
||||||
|
"title": "從外部導入",
|
||||||
|
"type": {
|
||||||
|
"url": "URL",
|
||||||
|
"file": "檔案"
|
||||||
|
},
|
||||||
|
"url_placeholder": "輸入 JSON URL",
|
||||||
|
"select_file": "選擇檔案",
|
||||||
|
"button": "導入",
|
||||||
|
"file_filter": "JSON 檔案",
|
||||||
|
"error": {
|
||||||
|
"url_required": "請輸入 URL",
|
||||||
|
"fetch_failed": "從 URL 獲取資料失敗",
|
||||||
|
"invalid_format": "無效的代理人格式:缺少必填欄位"
|
||||||
|
}
|
||||||
|
},
|
||||||
"delete.popup.content": "確定要刪除此智慧代理人嗎?",
|
"delete.popup.content": "確定要刪除此智慧代理人嗎?",
|
||||||
"edit.message.add.title": "新增",
|
"edit.message.add.title": "新增",
|
||||||
"edit.message.assistant.placeholder": "輸入助手訊息",
|
"edit.message.assistant.placeholder": "輸入助手訊息",
|
||||||
@ -498,6 +514,10 @@
|
|||||||
"title": "Mermaid 圖表"
|
"title": "Mermaid 圖表"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
|
"agents": {
|
||||||
|
"imported": "匯入成功",
|
||||||
|
"import.error": "匯入失敗"
|
||||||
|
},
|
||||||
"api.check.model.title": "請選擇要偵測的模型",
|
"api.check.model.title": "請選擇要偵測的模型",
|
||||||
"api.connection.failed": "連接失敗",
|
"api.connection.failed": "連接失敗",
|
||||||
"api.connection.success": "連接成功",
|
"api.connection.success": "連接成功",
|
||||||
|
|||||||
@ -53,7 +53,7 @@
|
|||||||
"settings.reasoning_effort.medium": "Moyen",
|
"settings.reasoning_effort.medium": "Moyen",
|
||||||
"settings.reasoning_effort.off": "Off",
|
"settings.reasoning_effort.off": "Off",
|
||||||
"settings.reasoning_effort.tip": "Prise en charge uniquement des modèles de raisonnement OpenAI o-series et Anthropic",
|
"settings.reasoning_effort.tip": "Prise en charge uniquement des modèles de raisonnement OpenAI o-series et Anthropic",
|
||||||
"title": "Aides"
|
"title": "Agent"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"error": "Échec de l'obtention automatique de la clé, veuillez la récupérer manuellement",
|
"error": "Échec de l'obtention automatique de la clé, veuillez la récupérer manuellement",
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { PlusOutlined } from '@ant-design/icons'
|
import { ImportOutlined, PlusOutlined } from '@ant-design/icons'
|
||||||
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
||||||
import CustomTag from '@renderer/components/CustomTag'
|
import CustomTag from '@renderer/components/CustomTag'
|
||||||
import ListItem from '@renderer/components/ListItem'
|
import ListItem from '@renderer/components/ListItem'
|
||||||
@ -20,6 +20,7 @@ import { groupTranslations } from './agentGroupTranslations'
|
|||||||
import AddAgentPopup from './components/AddAgentPopup'
|
import AddAgentPopup from './components/AddAgentPopup'
|
||||||
import AgentCard from './components/AgentCard'
|
import AgentCard from './components/AgentCard'
|
||||||
import { AgentGroupIcon } from './components/AgentGroupIcon'
|
import { AgentGroupIcon } from './components/AgentGroupIcon'
|
||||||
|
import ImportAgentPopup from './components/ImportAgentPopup'
|
||||||
|
|
||||||
const AgentsPage: FC = () => {
|
const AgentsPage: FC = () => {
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
@ -138,6 +139,17 @@ const AgentsPage: FC = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleImportAgent = async () => {
|
||||||
|
try {
|
||||||
|
await ImportAgentPopup.show()
|
||||||
|
} catch (error) {
|
||||||
|
window.message.error({
|
||||||
|
content: error instanceof Error ? error.message : t('message.agents.import.error'),
|
||||||
|
key: 'agents-import-error'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Navbar>
|
<Navbar>
|
||||||
@ -208,9 +220,14 @@ const AgentsPage: FC = () => {
|
|||||||
</CustomTag>
|
</CustomTag>
|
||||||
}
|
}
|
||||||
</AgentsListTitle>
|
</AgentsListTitle>
|
||||||
<Button type="text" onClick={handleAddAgent} icon={<PlusOutlined />}>
|
<Flex gap={8}>
|
||||||
{t('agents.add.title')}
|
<Button type="text" onClick={handleImportAgent} icon={<ImportOutlined />}>
|
||||||
</Button>
|
{t('agents.import.title')}
|
||||||
|
</Button>
|
||||||
|
<Button type="text" onClick={handleAddAgent} icon={<PlusOutlined />}>
|
||||||
|
{t('agents.add.title')}
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
</AgentsListHeader>
|
</AgentsListHeader>
|
||||||
|
|
||||||
{filteredAgents.length > 0 ? (
|
{filteredAgents.length > 0 ? (
|
||||||
|
|||||||
148
src/renderer/src/pages/agents/components/ImportAgentPopup.tsx
Normal file
148
src/renderer/src/pages/agents/components/ImportAgentPopup.tsx
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { TopView } from '@renderer/components/TopView'
|
||||||
|
import { useAgents } from '@renderer/hooks/useAgents'
|
||||||
|
import { getDefaultModel } from '@renderer/services/AssistantService'
|
||||||
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||||
|
import { Agent } from '@renderer/types'
|
||||||
|
import { uuid } from '@renderer/utils'
|
||||||
|
import { Button, Form, Input, Modal, Radio, Space } from 'antd'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
resolve: (value: Agent[] | null) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
||||||
|
const [open, setOpen] = useState(true)
|
||||||
|
const [form] = Form.useForm()
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { addAgent } = useAgents()
|
||||||
|
const [importType, setImportType] = useState<'url' | 'file'>('url')
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
|
const onFinish = async (values: { url?: string }) => {
|
||||||
|
setLoading(true)
|
||||||
|
try {
|
||||||
|
let agents: Agent[] = []
|
||||||
|
|
||||||
|
if (importType === 'url') {
|
||||||
|
if (!values.url) {
|
||||||
|
throw new Error(t('agents.import.error.url_required'))
|
||||||
|
}
|
||||||
|
const response = await fetch(values.url)
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(t('agents.import.error.fetch_failed'))
|
||||||
|
}
|
||||||
|
const data = await response.json()
|
||||||
|
agents = 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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and process agents
|
||||||
|
for (const agent of agents) {
|
||||||
|
if (!agent.name || !agent.prompt) {
|
||||||
|
throw new Error(t('agents.import.error.invalid_format'))
|
||||||
|
}
|
||||||
|
|
||||||
|
const newAgent: Agent = {
|
||||||
|
id: uuid(),
|
||||||
|
name: agent.name,
|
||||||
|
emoji: agent.emoji || '🤖',
|
||||||
|
group: agent.group || [],
|
||||||
|
prompt: agent.prompt,
|
||||||
|
description: agent.description || '',
|
||||||
|
type: 'agent',
|
||||||
|
topics: [],
|
||||||
|
messages: [],
|
||||||
|
defaultModel: getDefaultModel()
|
||||||
|
}
|
||||||
|
addAgent(newAgent)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.message.success({
|
||||||
|
content: t('message.agents.imported'),
|
||||||
|
key: 'agents-imported'
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(() => EventEmitter.emit(EVENT_NAMES.SHOW_ASSISTANTS), 0)
|
||||||
|
setOpen(false)
|
||||||
|
resolve(agents)
|
||||||
|
} catch (error) {
|
||||||
|
window.message.error({
|
||||||
|
content: error instanceof Error ? error.message : t('message.agents.import.error'),
|
||||||
|
key: 'agents-import-error'
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCancel = () => {
|
||||||
|
setOpen(false)
|
||||||
|
resolve(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal title={t('agents.import.title')} open={open} onCancel={onCancel} footer={null} centered>
|
||||||
|
<Form form={form} onFinish={onFinish} layout="vertical">
|
||||||
|
<Form.Item>
|
||||||
|
<Radio.Group value={importType} onChange={(e) => setImportType(e.target.value)}>
|
||||||
|
<Radio.Button value="url">{t('agents.import.type.url')}</Radio.Button>
|
||||||
|
<Radio.Button value="file">{t('agents.import.type.file')}</Radio.Button>
|
||||||
|
</Radio.Group>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
{importType === 'url' && (
|
||||||
|
<Form.Item name="url" rules={[{ required: true, message: t('agents.import.error.url_required') }]}>
|
||||||
|
<Input placeholder={t('agents.import.url_placeholder')} />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{importType === 'file' && (
|
||||||
|
<Form.Item>
|
||||||
|
<Button onClick={() => form.submit()}>{t('agents.import.select_file')}</Button>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Space>
|
||||||
|
<Button onClick={onCancel}>{t('common.cancel')}</Button>
|
||||||
|
<Button type="primary" onClick={() => form.submit()} loading={loading}>
|
||||||
|
{t('agents.import.button')}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ImportAgentPopup {
|
||||||
|
static show() {
|
||||||
|
return new Promise<Agent[] | null>((resolve) => {
|
||||||
|
TopView.show(
|
||||||
|
<PopupContainer
|
||||||
|
resolve={(v) => {
|
||||||
|
resolve(v)
|
||||||
|
this.hide()
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
'ImportAgentPopup'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static hide() {
|
||||||
|
TopView.hide('ImportAgentPopup')
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,7 @@
|
|||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { Agent } from '@renderer/types'
|
import { Agent } from '@renderer/types'
|
||||||
import { runAsyncFunction } from '@renderer/utils'
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
let _agents: Agent[] = []
|
let _agents: Agent[] = []
|
||||||
|
|
||||||
export const getAgentsFromSystemAgents = (systemAgents: any) => {
|
export const getAgentsFromSystemAgents = (systemAgents: any) => {
|
||||||
@ -17,17 +16,30 @@ export const getAgentsFromSystemAgents = (systemAgents: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useSystemAgents() {
|
export function useSystemAgents() {
|
||||||
const [agents, setAgents] = useState<Agent[]>(_agents)
|
const { defaultAgent } = useSettings()
|
||||||
|
const [agents, setAgents] = useState<Agent[]>([])
|
||||||
const { resourcesPath } = useRuntime()
|
const { resourcesPath } = useRuntime()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
runAsyncFunction(async () => {
|
const loadAgents = async () => {
|
||||||
if (!resourcesPath || _agents.length > 0) return
|
try {
|
||||||
const agents = await window.api.fs.read(resourcesPath + '/data/agents.json')
|
// 始终加载本地 agents
|
||||||
_agents = JSON.parse(agents) as Agent[]
|
if (resourcesPath && _agents.length === 0) {
|
||||||
setAgents(_agents)
|
const localAgentsData = await window.api.fs.read(resourcesPath + '/data/agents.json')
|
||||||
})
|
_agents = JSON.parse(localAgentsData) as Agent[]
|
||||||
}, [resourcesPath])
|
}
|
||||||
|
|
||||||
|
// 如果没有远程配置或获取失败,使用本地 agents
|
||||||
|
setAgents(_agents)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load agents:', error)
|
||||||
|
// 发生错误时使用本地 agents
|
||||||
|
setAgents(_agents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAgents()
|
||||||
|
}, [defaultAgent, resourcesPath])
|
||||||
|
|
||||||
return agents
|
return agents
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,6 +104,7 @@ export interface SettingsState {
|
|||||||
joplinToken: string | null
|
joplinToken: string | null
|
||||||
joplinUrl: string | null
|
joplinUrl: string | null
|
||||||
defaultObsidianVault: string | null
|
defaultObsidianVault: string | null
|
||||||
|
defaultAgent: string | null
|
||||||
// 思源笔记配置
|
// 思源笔记配置
|
||||||
siyuanApiUrl: string | null
|
siyuanApiUrl: string | null
|
||||||
siyuanToken: string | null
|
siyuanToken: string | null
|
||||||
@ -210,6 +211,7 @@ export const initialState: SettingsState = {
|
|||||||
joplinToken: '',
|
joplinToken: '',
|
||||||
joplinUrl: '',
|
joplinUrl: '',
|
||||||
defaultObsidianVault: null,
|
defaultObsidianVault: null,
|
||||||
|
defaultAgent: null,
|
||||||
siyuanApiUrl: null,
|
siyuanApiUrl: null,
|
||||||
siyuanToken: null,
|
siyuanToken: null,
|
||||||
siyuanBoxId: null,
|
siyuanBoxId: null,
|
||||||
@ -465,6 +467,15 @@ const settingsSlice = createSlice({
|
|||||||
setJoplinUrl: (state, action: PayloadAction<string>) => {
|
setJoplinUrl: (state, action: PayloadAction<string>) => {
|
||||||
state.joplinUrl = action.payload
|
state.joplinUrl = action.payload
|
||||||
},
|
},
|
||||||
|
setMessageNavigation: (state, action: PayloadAction<'none' | 'buttons' | 'anchor'>) => {
|
||||||
|
state.messageNavigation = action.payload
|
||||||
|
},
|
||||||
|
setDefaultObsidianVault: (state, action: PayloadAction<string>) => {
|
||||||
|
state.defaultObsidianVault = action.payload
|
||||||
|
},
|
||||||
|
setDefaultAgent: (state, action: PayloadAction<string>) => {
|
||||||
|
state.defaultAgent = action.payload
|
||||||
|
},
|
||||||
setSiyuanApiUrl: (state, action: PayloadAction<string>) => {
|
setSiyuanApiUrl: (state, action: PayloadAction<string>) => {
|
||||||
state.siyuanApiUrl = action.payload
|
state.siyuanApiUrl = action.payload
|
||||||
},
|
},
|
||||||
@ -477,12 +488,6 @@ const settingsSlice = createSlice({
|
|||||||
setSiyuanRootPath: (state, action: PayloadAction<string>) => {
|
setSiyuanRootPath: (state, action: PayloadAction<string>) => {
|
||||||
state.siyuanRootPath = action.payload
|
state.siyuanRootPath = action.payload
|
||||||
},
|
},
|
||||||
setMessageNavigation: (state, action: PayloadAction<'none' | 'buttons' | 'anchor'>) => {
|
|
||||||
state.messageNavigation = action.payload
|
|
||||||
},
|
|
||||||
setDefaultObsidianVault: (state, action: PayloadAction<string>) => {
|
|
||||||
state.defaultObsidianVault = action.payload
|
|
||||||
},
|
|
||||||
setMaxKeepAliveMinapps: (state, action: PayloadAction<number>) => {
|
setMaxKeepAliveMinapps: (state, action: PayloadAction<number>) => {
|
||||||
state.maxKeepAliveMinapps = action.payload
|
state.maxKeepAliveMinapps = action.payload
|
||||||
},
|
},
|
||||||
@ -584,6 +589,7 @@ export const {
|
|||||||
setJoplinUrl,
|
setJoplinUrl,
|
||||||
setMessageNavigation,
|
setMessageNavigation,
|
||||||
setDefaultObsidianVault,
|
setDefaultObsidianVault,
|
||||||
|
setDefaultAgent,
|
||||||
setSiyuanApiUrl,
|
setSiyuanApiUrl,
|
||||||
setSiyuanToken,
|
setSiyuanToken,
|
||||||
setSiyuanBoxId,
|
setSiyuanBoxId,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user