196 lines
6.1 KiB
TypeScript
196 lines
6.1 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import { Form, Button } from 'antd';
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
import { App as AntApp } from 'antd';
|
|
import { FileTextOutlined, SaveOutlined } from '@ant-design/icons';
|
|
import SkillEditor from '../../components/SkillEditor';
|
|
import ExternalToolEditor from '../../components/ExternalToolEditor';
|
|
import { useAgentEditor } from './hooks/useAgentEditor';
|
|
import { useIsMobile } from '../../hooks/useIsMobile';
|
|
import Header from './components/Header';
|
|
import PromptEditor from './components/PromptEditor';
|
|
import CapabilitySettings from './components/CapabilitySettings';
|
|
import PreviewPane from './components/PreviewPane';
|
|
import InitModal from './components/InitModal';
|
|
import AvatarSelector from './components/AvatarSelector';
|
|
import './AgentEditor.css';
|
|
import './styles/agent-editor-capability.css';
|
|
import './styles/agent-editor-panels.css';
|
|
import './styles/agent-editor-modal.css';
|
|
import './styles/agent-editor-h5.css';
|
|
|
|
export default function AgentEditor() {
|
|
const { id } = useParams();
|
|
const isNew = !id;
|
|
const navigate = useNavigate();
|
|
const { message } = AntApp.useApp();
|
|
const [form] = Form.useForm();
|
|
const [externalToolEditorOpen, setExternalToolEditorOpen] = useState(false);
|
|
const [editingPluginId, setEditingPluginId] = useState<string | null>(null);
|
|
|
|
const {
|
|
agent,
|
|
saving,
|
|
teams,
|
|
models,
|
|
autoSaveStatus,
|
|
initModalOpen,
|
|
setInitModalOpen,
|
|
selectedAvatar,
|
|
setSelectedAvatar,
|
|
avatarSelectorOpen,
|
|
setAvatarSelectorOpen,
|
|
avatarUploading,
|
|
agentName,
|
|
setAgentName,
|
|
skillEditorOpen,
|
|
setSkillEditorOpen,
|
|
editingSkillId,
|
|
setEditingSkillId,
|
|
refresh,
|
|
handleInitConfirm,
|
|
handleSave,
|
|
beforeUploadKnowledge,
|
|
beforeUploadInitAvatar,
|
|
beforeUploadEditAvatar,
|
|
handleAvatarSelect,
|
|
handleDeleteKnowledge,
|
|
handleDeleteSkill,
|
|
handleDeletePlugin,
|
|
liveAgent,
|
|
currentName,
|
|
markDirty,
|
|
} = useAgentEditor({ id, isNew, form, message, navigate });
|
|
|
|
const isMobile = useIsMobile();
|
|
|
|
return (
|
|
<>
|
|
<div className="agent-editor-shell-container">
|
|
<Header
|
|
isNew={isNew}
|
|
currentName={currentName}
|
|
navigate={navigate}
|
|
autoSaveStatus={autoSaveStatus}
|
|
saving={saving}
|
|
onSave={handleSave}
|
|
isMobile={isMobile}
|
|
/>
|
|
|
|
<div className={`agent-editor-workbench-container ${isMobile ? 'is-mobile' : 'is-desktop'}`}>
|
|
<PromptEditor form={form} markDirty={markDirty} />
|
|
<CapabilitySettings
|
|
form={form}
|
|
agent={agent}
|
|
teams={teams}
|
|
models={models}
|
|
currentName={currentName}
|
|
agentName={agentName}
|
|
selectedAvatar={agent?.avatar || selectedAvatar}
|
|
setAvatarSelectorOpen={setAvatarSelectorOpen}
|
|
beforeUploadKnowledge={beforeUploadKnowledge}
|
|
onDeleteKnowledge={handleDeleteKnowledge}
|
|
onCreateSkill={() => {
|
|
setEditingSkillId(null);
|
|
setSkillEditorOpen(true);
|
|
}}
|
|
onEditSkill={(skillId) => {
|
|
setEditingSkillId(skillId);
|
|
setSkillEditorOpen(true);
|
|
}}
|
|
onDeleteSkill={handleDeleteSkill}
|
|
onCreateExternalTool={() => {
|
|
setEditingPluginId(null);
|
|
setExternalToolEditorOpen(true);
|
|
}}
|
|
onEditExternalTool={(pluginId) => {
|
|
setEditingPluginId(pluginId);
|
|
setExternalToolEditorOpen(true);
|
|
}}
|
|
onDeleteExternalTool={handleDeletePlugin}
|
|
markDirty={markDirty}
|
|
isMobile={isMobile}
|
|
/>
|
|
<PreviewPane liveAgent={liveAgent} agentId={id} />
|
|
</div>
|
|
|
|
{isMobile && (
|
|
<div className="agent-editor-mobile-footer-bar">
|
|
<span className="agent-editor-footer-status">
|
|
{autoSaveStatus === 'saving'
|
|
? '正在保存...'
|
|
: autoSaveStatus === 'dirty'
|
|
? '有未保存更改'
|
|
: autoSaveStatus === 'error'
|
|
? '保存失败'
|
|
: '已保存'}
|
|
</span>
|
|
<div className="agent-editor-footer-actions">
|
|
<Button icon={<FileTextOutlined />} size="middle">
|
|
文档
|
|
</Button>
|
|
<Button
|
|
type="primary"
|
|
icon={<SaveOutlined />}
|
|
loading={saving}
|
|
onClick={() => handleSave()}
|
|
size="middle"
|
|
>
|
|
保存
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{!isNew && (
|
|
<>
|
|
<SkillEditor
|
|
open={skillEditorOpen}
|
|
agentId={id!}
|
|
skillId={editingSkillId}
|
|
onClose={() => {
|
|
setSkillEditorOpen(false);
|
|
setEditingSkillId(null);
|
|
}}
|
|
onSaved={refresh}
|
|
/>
|
|
<ExternalToolEditor
|
|
open={externalToolEditorOpen}
|
|
agentId={id!}
|
|
plugin={agent?.plugins?.find((plugin) => plugin.id === editingPluginId)}
|
|
onClose={() => {
|
|
setExternalToolEditorOpen(false);
|
|
setEditingPluginId(null);
|
|
}}
|
|
onSaved={refresh}
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
<InitModal
|
|
isMobile={isMobile}
|
|
open={initModalOpen}
|
|
onCancel={() => navigate('/agents')}
|
|
onConfirm={handleInitConfirm}
|
|
avatarUploading={avatarUploading}
|
|
selectedAvatar={selectedAvatar}
|
|
setSelectedAvatar={setSelectedAvatar}
|
|
agentName={agentName}
|
|
setAgentName={setAgentName}
|
|
saving={saving}
|
|
beforeUploadInitAvatar={beforeUploadInitAvatar}
|
|
/>
|
|
|
|
<AvatarSelector
|
|
open={avatarSelectorOpen}
|
|
onCancel={() => setAvatarSelectorOpen(false)}
|
|
agent={agent}
|
|
avatarUploading={avatarUploading}
|
|
beforeUploadEditAvatar={beforeUploadEditAvatar}
|
|
onAvatarSelect={handleAvatarSelect}
|
|
/>
|
|
</>
|
|
);
|
|
}
|