aura-web/src/pages/AgentEditor/components/capability/KnowledgeSettingsPanel.tsx

258 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { ApiOutlined, DatabaseOutlined, DeleteOutlined, EditOutlined, PlusOutlined, ToolOutlined } from '@ant-design/icons';
import { Button, Card, Collapse, Input, List, Popconfirm, Space, Tag } from 'antd';
import { Agent } from '../../../../api';
import { STATUS_TAG } from '../../constants';
interface KnowledgeSettingsPanelProps {
agent: Agent | null;
beforeUploadKnowledge: (file: any) => Promise<boolean>;
onDeleteKnowledge: (fileId: string) => Promise<void>;
onCreateSkill: () => void;
onEditSkill: (skillId: string) => void;
onDeleteSkill: (skillId: string) => Promise<void>;
onCreateExternalTool: () => void;
onEditExternalTool: (pluginId: string) => void;
onDeleteExternalTool: (pluginId: string) => Promise<void>;
}
export default function KnowledgeSettingsPanel({
agent,
beforeUploadKnowledge,
onDeleteKnowledge,
onCreateSkill,
onEditSkill,
onDeleteSkill,
onCreateExternalTool,
onEditExternalTool,
onDeleteExternalTool,
}: KnowledgeSettingsPanelProps) {
const skills = agent?.skills ?? [];
const plugins = agent?.plugins ?? [];
return (
<Collapse
ghost
expandIconPosition="end"
className="monica-collapse"
items={[
{
key: 'knowledge',
label: (
<div className="agent-editor-collapse-label">
<DatabaseOutlined className="agent-editor-label-icon" />
({agent?.knowledge?.length ?? 0})
</div>
),
children: (
<div className="px-1">
<div className="flex justify-between items-center mb-4">
<span className="text-xs text-gray-500"> AI </span>
<input
type="file"
multiple
style={{ display: 'none' }}
id="knowledge-upload"
onChange={async (event) => {
const files = event.target.files;
if (!files) return;
for (let index = 0; index < files.length; index++) {
await beforeUploadKnowledge(files[index]);
}
event.target.value = '';
}}
/>
<Button
type="primary"
size="small"
ghost
icon={<DatabaseOutlined />}
className="agent-editor-small-action"
onClick={() => document.getElementById('knowledge-upload')?.click()}
>
</Button>
</div>
<List
size="small"
dataSource={agent?.knowledge ?? []}
renderItem={(item) => (
<List.Item
className="bg-white mb-2 rounded-lg border border-gray-100 p-2"
actions={[
<Popconfirm key="del" title="确认删除?" onConfirm={() => onDeleteKnowledge(item.id)}>
<Button type="text" danger size="small" className="agent-editor-danger-action">
</Button>
</Popconfirm>,
]}
>
<div className="flex flex-col gap-1 overflow-hidden">
<span className="text-sm font-medium truncate">{item.originalName}</span>
<span className="text-[10px] text-gray-400">
{item.size ? `${(item.size / 1024).toFixed(1)} KB` : ''} ·{' '}
{item.status === 'indexing' ? (
<Tag color="processing" className="m-0 text-[10px] px-1">
<span className="agent-editor-indexing-label"></span>
</Tag>
) : (
<Tag
color={STATUS_TAG[item.status as keyof typeof STATUS_TAG]?.color || 'default'}
className="m-0 text-[10px] px-1"
>
{STATUS_TAG[item.status as keyof typeof STATUS_TAG]?.text || item.status || '未知'}
</Tag>
)}
</span>
</div>
</List.Item>
)}
/>
</div>
),
},
{
key: 'skills',
label: (
<div className="agent-editor-collapse-label">
<ToolOutlined className="agent-editor-label-icon" />
& ({skills.length + plugins.length})
</div>
),
children: (
<div className="px-1">
<div className="agent-editor-skill-actions">
<span className="text-xs text-gray-500">Markdown API </span>
<Space wrap>
<Button size="small" icon={<PlusOutlined />} onClick={onCreateSkill}>
Skill
</Button>
<Button type="primary" ghost size="small" icon={<ApiOutlined />} onClick={onCreateExternalTool}>
</Button>
</Space>
</div>
<div className="agent-editor-tool-section">
<div className="agent-editor-tool-section-title">
<span>Skills</span>
<Tag>{skills.length}</Tag>
</div>
<List
size="small"
locale={{ emptyText: '暂无 Markdown Skill' }}
dataSource={skills}
renderItem={(item) => (
<List.Item
className="agent-editor-skill-item"
actions={[
<Button key="edit" type="text" size="small" icon={<EditOutlined />} onClick={() => onEditSkill(item.id)}>
</Button>,
<Popconfirm key="delete" title="确认删除该 Skill" onConfirm={() => onDeleteSkill(item.id)}>
<Button type="text" danger size="small" icon={<DeleteOutlined />}>
</Button>
</Popconfirm>,
]}
>
<List.Item.Meta
title={<span className="agent-editor-skill-name">{item.filename || item.name}</span>}
description={
<div>
<div>{item.description || '暂无描述'}</div>
{item.filename && item.filename !== item.name && <div className="agent-editor-tool-help">{item.name}</div>}
</div>
}
/>
<Space size={6} wrap>
<Tag color="blue">{item.type}</Tag>
<Tag color={item.enabled ? 'success' : 'default'}>{item.enabled ? '已启用' : '未启用'}</Tag>
</Space>
</List.Item>
)}
/>
</div>
<div className="agent-editor-tool-section">
<div className="agent-editor-tool-section-title">
<span></span>
<Tag>{plugins.length}</Tag>
</div>
{plugins.length === 0 ? (
<div className="agent-editor-tool-empty"></div>
) : (
<Space direction="vertical" size={10} className="agent-editor-tool-list">
{plugins.map((plugin) => (
<Card
key={plugin.id}
size="small"
className="agent-editor-plugin-card"
title={
<Space wrap>
<ApiOutlined className="agent-editor-label-icon" />
<span>{plugin.name}</span>
<Tag color={plugin.enabled ? 'success' : 'default'}>{plugin.enabled ? '已启用' : '未启用'}</Tag>
</Space>
}
extra={
<Space>
<Button type="text" size="small" icon={<EditOutlined />} onClick={() => onEditExternalTool(plugin.id)}>
</Button>
<Popconfirm title="确认删除该工具集及其全部 API" onConfirm={() => onDeleteExternalTool(plugin.id)}>
<Button type="text" danger size="small" icon={<DeleteOutlined />}>
</Button>
</Popconfirm>
</Space>
}
>
<div className="agent-editor-plugin-description">{plugin.description || '暂无描述'}</div>
<Space size={6} wrap className="agent-editor-plugin-meta">
<Tag>{plugin.authType || 'none'}</Tag>
<span>{plugin.baseUrl}</span>
<span>{plugin.apis?.length ?? 0} API</span>
</Space>
<Collapse
ghost
size="small"
className="agent-editor-plugin-apis"
items={plugin.apis?.map((api) => ({
key: api.id || api.name,
label: (
<Space wrap>
<Tag color="geekblue">{api.method}</Tag>
<strong>{api.name}</strong>
<span className="agent-editor-tool-help">{api.path}</span>
</Space>
),
children: (
<div className="agent-editor-api-detail">
<div>{api.description || '暂无描述'}</div>
<div className="agent-editor-api-config-grid">
<div>
<strong>headers</strong>
<pre>{JSON.stringify(api.headers || {}, null, 2)}</pre>
</div>
<div>
<strong>parametersSchema</strong>
<pre>{JSON.stringify(api.parametersSchema || {}, null, 2)}</pre>
</div>
</div>
</div>
),
})) || []}
/>
</Card>
))}
</Space>
)}
</div>
</div>
),
},
]}
/>
);
}