feat: 添加自定义Agent管理功能

- 在工具注册表下方添加自定义Agent管理卡片
- 支持查看自定义Agent列表(名称、模板、状态、CPU、内存、运行时间)
- 支持停止运行中的Agent
- 支持重启/启动Agent
- 支持删除Agent(带确认提示)
- 添加刷新按钮手动更新列表
- 添加API方法:getUserCustomAgents, deleteCustomAgent, stopCustomAgent, restartCustomAgent
This commit is contained in:
xiaohei
2026-01-09 16:17:21 +00:00
parent c87dc658f0
commit 5e97eb40cb
2 changed files with 257 additions and 1 deletions
+207 -1
View File
@@ -12,7 +12,7 @@ import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Badge } from "@/components/ui/badge"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Plus, Search, ExternalLink, Trash2, FileJson, Cloud, Cpu, Code2, Boxes, Workflow, Upload } from "lucide-react"
import { Plus, Search, ExternalLink, Trash2, FileJson, Cloud, Cpu, Code2, Boxes, Workflow, Upload, RefreshCw, Square, Play, Bot } from "lucide-react"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import {
Dialog,
@@ -47,10 +47,16 @@ export default function DataToolsPage() {
const [selectedServiceGateway, setSelectedServiceGateway] = useState<string>("")
const [selectedDataTemplate, setSelectedDataTemplate] = useState<string>("")
const [dataTemplates, setDataTemplates] = useState<any[]>([])
// 自定义Agent管理状态
const [customAgents, setCustomAgents] = useState<any[]>([])
const [customAgentsLoading, setCustomAgentsLoading] = useState(true)
const [actionLoading, setActionLoading] = useState<string | null>(null)
useEffect(() => {
loadTools()
loadStats()
loadCustomAgents()
}, [])
const loadTools = async () => {
@@ -84,6 +90,88 @@ export default function DataToolsPage() {
}
}
// 加载自定义Agent列表
const loadCustomAgents = async () => {
try {
setCustomAgentsLoading(true)
const result = await TaijiAPIClient.getUserCustomAgents()
if (result?.success && result.data?.agents) {
setCustomAgents(result.data.agents)
}
} catch (error) {
console.error("Failed to load custom agents:", error)
} finally {
setCustomAgentsLoading(false)
}
}
// 删除自定义Agent
const handleDeleteCustomAgent = async (agentName: string) => {
if (!confirm(t(`确定要删除Agent "${agentName}" 吗?此操作不可恢复。`, `Are you sure you want to delete agent "${agentName}"? This action cannot be undone.`))) {
return
}
try {
setActionLoading(agentName)
const result = await TaijiAPIClient.deleteCustomAgent(agentName)
if (result?.success) {
loadCustomAgents()
}
} catch (error) {
console.error("Failed to delete custom agent:", error)
} finally {
setActionLoading(null)
}
}
// 停止自定义Agent
const handleStopCustomAgent = async (agentName: string) => {
if (!confirm(t(`确定要停止Agent "${agentName}" 吗?`, `Are you sure you want to stop agent "${agentName}"?`))) {
return
}
try {
setActionLoading(agentName)
const result = await TaijiAPIClient.stopCustomAgent(agentName)
if (result?.success) {
loadCustomAgents()
}
} catch (error) {
console.error("Failed to stop custom agent:", error)
} finally {
setActionLoading(null)
}
}
// 重启自定义Agent
const handleRestartCustomAgent = async (agentName: string) => {
try {
setActionLoading(agentName)
const result = await TaijiAPIClient.restartCustomAgent(agentName)
if (result?.success) {
loadCustomAgents()
}
} catch (error) {
console.error("Failed to restart custom agent:", error)
} finally {
setActionLoading(null)
}
}
// 获取状态颜色
const getStatusColor = (status: string) => {
switch (status?.toLowerCase()) {
case "running":
return "bg-green-500/10 text-green-500"
case "stopped":
return "bg-gray-500/10 text-gray-500"
case "pending":
return "bg-yellow-500/10 text-yellow-500"
case "failed":
return "bg-red-500/10 text-red-500"
default:
return "bg-gray-500/10 text-gray-500"
}
}
return (
<AuthGuard>
<DashboardLayout>
@@ -239,6 +327,124 @@ export default function DataToolsPage() {
</Table>
</CardContent>
</Card>
{/* 自定义Agent管理 */}
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="flex items-center gap-2">
<Bot className="h-5 w-5" />
{t("自定义Agent管理", "Custom Agent Management")}
</CardTitle>
<CardDescription>
{t("管理已部署的自定义Agent,支持停止、重启和删除操作", "Manage deployed custom agents with stop, restart and delete operations")}
</CardDescription>
</div>
<Button variant="outline" size="sm" onClick={loadCustomAgents} className="gap-2">
<RefreshCw className="h-4 w-4" />
{t("刷新", "Refresh")}
</Button>
</div>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>{t("Agent名称", "Agent Name")}</TableHead>
<TableHead>{t("模板", "Template")}</TableHead>
<TableHead>{t("状态", "Status")}</TableHead>
<TableHead>{t("CPU", "CPU")}</TableHead>
<TableHead>{t("内存", "Memory")}</TableHead>
<TableHead>{t("运行时间", "Runtime")}</TableHead>
<TableHead className="text-right">{t("操作", "Actions")}</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{customAgentsLoading ? (
<TableRow>
<TableCell colSpan={7} className="text-center py-8">
<span className="text-muted-foreground">{t("加载中...", "Loading...")}</span>
</TableCell>
</TableRow>
) : customAgents.length === 0 ? (
<TableRow>
<TableCell colSpan={7} className="text-center py-8">
<span className="text-muted-foreground">{t("暂无自定义Agent", "No custom agents")}</span>
</TableCell>
</TableRow>
) : (
customAgents.map((agent) => (
<TableRow key={agent.name}>
<TableCell className="font-medium">{agent.name}</TableCell>
<TableCell>
<Badge variant="secondary">{agent.template || "-"}</Badge>
</TableCell>
<TableCell>
<Badge className={getStatusColor(agent.status)}>
{agent.status || "Unknown"}
</Badge>
</TableCell>
<TableCell className="text-sm">{agent.cpu || "-"}</TableCell>
<TableCell className="text-sm">{agent.memory || "-"}</TableCell>
<TableCell className="text-sm text-muted-foreground">
{agent.runningSeconds
? `${Math.floor(agent.runningSeconds / 3600)}h ${Math.floor((agent.runningSeconds % 3600) / 60)}m`
: "-"
}
</TableCell>
<TableCell className="text-right">
<div className="flex justify-end gap-1">
{agent.status?.toLowerCase() === "running" ? (
<>
<Button
variant="ghost"
size="icon"
title={t("停止", "Stop")}
disabled={actionLoading === agent.name}
onClick={() => handleStopCustomAgent(agent.name)}
>
<Square className="h-4 w-4 text-yellow-500" />
</Button>
<Button
variant="ghost"
size="icon"
title={t("重启", "Restart")}
disabled={actionLoading === agent.name}
onClick={() => handleRestartCustomAgent(agent.name)}
>
<RefreshCw className="h-4 w-4 text-blue-500" />
</Button>
</>
) : (
<Button
variant="ghost"
size="icon"
title={t("启动", "Start")}
disabled={actionLoading === agent.name}
onClick={() => handleRestartCustomAgent(agent.name)}
>
<Play className="h-4 w-4 text-green-500" />
</Button>
)}
<Button
variant="ghost"
size="icon"
title={t("删除", "Delete")}
disabled={actionLoading === agent.name}
onClick={() => handleDeleteCustomAgent(agent.name)}
>
<Trash2 className="h-4 w-4 text-destructive" />
</Button>
</div>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="templates" className="space-y-4">
+50
View File
@@ -519,6 +519,56 @@ export class TaijiAPIClient {
return handleResponse(response)
}
/**
* 获取用户自定义Agent列表(别名)
* GET /api/user/custom-agents
*/
static async getUserCustomAgents() {
return this.getCustomAgents()
}
/**
* 删除自定义Agent
* DELETE /api/user/custom-agents/{name}
*
* @param agentName - Agent名称
*/
static async deleteCustomAgent(agentName: string) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/user/custom-agents/${agentName}`, {
method: "DELETE",
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 停止自定义Agent
* POST /api/user/custom-agents/{name}/stop
*
* @param agentName - Agent名称
*/
static async stopCustomAgent(agentName: string) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/user/custom-agents/${agentName}/stop`, {
method: "POST",
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 重启自定义Agent
* POST /api/user/custom-agents/{name}/restart
*
* @param agentName - Agent名称
*/
static async restartCustomAgent(agentName: string) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/user/custom-agents/${agentName}/restart`, {
method: "POST",
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 获取工作流列表
* GET /api/user/workflows/list