feat: Day 10-11 - Agent Configuration System completed

Backend:
- Create agents.yaml config file with 12 agents definition
- Create Prompt templates for topic-evaluation agent
- Implement agentService.ts for loading and managing agent configs
- Create agentController.ts with CRUD operations
- Create agent routes (GET /agents, /agents/:id, etc.)
- Register agent routes in main server

Frontend:
- Create agentApi.ts service module
- Update AgentChatPage to dynamically load agent config from API
- Add loading state and error handling
- Display agent details (description, category, model)

Build: Both frontend and backend build successfully
This commit is contained in:
AI Clinical Dev Team
2025-10-10 20:13:08 +08:00
parent 59522eaab7
commit 864a0b1906
13 changed files with 1077 additions and 13 deletions

View File

@@ -0,0 +1,77 @@
import request from './request';
export interface AgentConfig {
id: string;
name: string;
nameEn: string;
description: string;
category: string;
icon: string;
enabled: boolean;
systemPromptFile: string;
userPromptTemplateFile: string;
models: {
[modelName: string]: {
temperature: number;
maxTokens: number;
topP?: number;
};
};
ragEnabled: boolean;
requiresProject: boolean;
outputFormat: 'text' | 'structured' | 'document';
tags: string[];
}
export interface ApiResponse<T = any> {
success: boolean;
data?: T;
message?: string;
error?: string;
}
export const agentApi = {
// 获取所有智能体列表
getAll: async (): Promise<ApiResponse<AgentConfig[]>> => {
const response = await request.get('/agents');
return response.data;
},
// 获取启用的智能体列表
getEnabled: async (): Promise<ApiResponse<AgentConfig[]>> => {
const response = await request.get('/agents/enabled');
return response.data;
},
// 获取单个智能体详情
getById: async (id: string): Promise<ApiResponse<AgentConfig>> => {
const response = await request.get(`/agents/${id}`);
return response.data;
},
// 根据分类获取智能体
getByCategory: async (category: string): Promise<ApiResponse<AgentConfig[]>> => {
const response = await request.get(`/agents/by-category?category=${encodeURIComponent(category)}`);
return response.data;
},
// 获取智能体的系统Prompt
getSystemPrompt: async (id: string): Promise<ApiResponse<{ agentId: string; systemPrompt: string }>> => {
const response = await request.get(`/agents/${id}/system-prompt`);
return response.data;
},
// 渲染用户Prompt
renderPrompt: async (
id: string,
data: {
projectBackground?: string;
userInput: string;
knowledgeBaseContext?: string;
}
): Promise<ApiResponse<{ agentId: string; renderedPrompt: string }>> => {
const response = await request.post(`/agents/${id}/render-prompt`, data);
return response.data;
},
};

View File

@@ -1,5 +1,6 @@
import { useParams } from 'react-router-dom'
import { Card, Typography, Input, Button, Space, Select, Upload, Tag, Alert, Divider } from 'antd'
import { useState, useEffect } from 'react'
import { Card, Typography, Input, Button, Space, Select, Upload, Tag, Alert, Divider, Spin } from 'antd'
import {
SendOutlined,
PaperClipOutlined,
@@ -7,20 +8,57 @@ import {
FolderOpenOutlined,
SyncOutlined,
} from '@ant-design/icons'
import { AGENTS } from '../layouts/MainLayout'
import { agentApi, type AgentConfig } from '../api/agentApi'
import { message } from 'antd'
const { Title, Paragraph } = Typography
const { TextArea } = Input
const AgentChatPage = () => {
const { agentId } = useParams()
const agent = AGENTS.find((a) => a.id === agentId)
const [agent, setAgent] = useState<AgentConfig | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
if (!agent) {
// 加载智能体配置
useEffect(() => {
const fetchAgent = async () => {
if (!agentId) return
try {
setLoading(true)
const response = await agentApi.getById(agentId)
if (response.success && response.data) {
setAgent(response.data)
} else {
setError(response.message || '智能体不存在')
}
} catch (err) {
console.error('Failed to load agent:', err)
setError('加载智能体配置失败')
message.error('加载智能体配置失败')
} finally {
setLoading(false)
}
}
fetchAgent()
}, [agentId])
if (loading) {
return (
<div style={{ textAlign: 'center', padding: '100px 0' }}>
<Spin size="large" tip="加载智能体配置中..." />
</div>
)
}
if (error || !agent) {
return (
<Alert
message="智能体不存在"
description="请从首页选择一个智能体"
description={error || "请从首页选择一个智能体"}
type="error"
showIcon
/>
@@ -49,7 +87,10 @@ const AgentChatPage = () => {
{agent.name}
</Title>
<Paragraph type="secondary" style={{ marginBottom: 0 }}>
DeepSeek-V3
{agent.description}
</Paragraph>
<Paragraph type="secondary" style={{ marginBottom: 0, fontSize: 12 }}>
DeepSeek-V3 | {agent.category}
</Paragraph>
</div>
</Space>