feat: add workflow version fetching functionality and enhance AIAgentConfigWorkbench display

This commit is contained in:
mlogclub
2026-06-22 22:39:49 +08:00
parent 9b76ef4bd0
commit 3e68fc3344
3 changed files with 100 additions and 31 deletions
@@ -25,6 +25,14 @@ import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { Textarea } from "@/components/ui/textarea"
import {
createAIAgent,
@@ -32,6 +40,7 @@ import {
fetchAIAgentWorkflow,
fetchAIConfigsAll,
fetchAIWorkflowNodeSpecs,
fetchAIWorkflowVersions,
fetchAgentTeamsAll,
fetchKnowledgeBasesAll,
fetchMCPCatalog,
@@ -45,6 +54,7 @@ import {
type AIWorkflow,
type AIWorkflowDefinition,
type AIWorkflowNodeSpec,
type AIWorkflowVersion,
type AIWorkflowValidationResult,
type AdminAgentTeam,
type CreateAIAgentPayload,
@@ -162,6 +172,7 @@ export function AIAgentConfigWorkbench({
const [activeSection, setActiveSection] = useState<SectionKey>("basic")
const [agent, setAgent] = useState<AIAgent | null>(null)
const [workflow, setWorkflow] = useState<AIWorkflow | null>(null)
const [workflowVersions, setWorkflowVersions] = useState<AIWorkflowVersion[]>([])
const [nodeSpecs, setNodeSpecs] = useState<AIWorkflowNodeSpec[]>([])
const [validation, setValidation] = useState<AIWorkflowValidationResult | null>(null)
const [loading, setLoading] = useState(true)
@@ -234,6 +245,7 @@ export function AIAgentConfigWorkbench({
if (!currentAgentId || currentAgentId <= 0) {
setAgent(null)
setWorkflow(null)
setWorkflowVersions([])
setName("")
setDescription("")
setAIConfigId("")
@@ -260,6 +272,12 @@ export function AIAgentConfigWorkbench({
setAgent(agentDetail)
setWorkflow(workflowDetail)
if (workflowDetail?.id > 0) {
const versionPage = await fetchAIWorkflowVersions({ workflowId: workflowDetail.id, limit: 20 })
setWorkflowVersions(versionPage.results ?? [])
} else {
setWorkflowVersions([])
}
setName(agentDetail.name)
setDescription(agentDetail.description || "")
setAIConfigId(toText(agentDetail.aiConfigId))
@@ -600,7 +618,7 @@ export function AIAgentConfigWorkbench({
) : (
<div className={activeSection === "workflow" ? "h-full min-h-0" : "w-full p-6"}>
{activeSection === "basic" ? (
<ConfigSection title="基础信息" description="定义这个 Agent 在渠道和后台中的基础身份。">
<ConfigSection>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<FieldBlock label="名称">
<Input value={name} onChange={(event) => setName(event.target.value)} />
@@ -621,7 +639,7 @@ export function AIAgentConfigWorkbench({
) : null}
{activeSection === "model" ? (
<ConfigSection title="模型与 Prompt" description="配置模型、系统提示词和首响内容。">
<ConfigSection>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<FieldBlock label="AI 配置">
<OptionCombobox
@@ -658,7 +676,7 @@ export function AIAgentConfigWorkbench({
) : null}
{activeSection === "knowledge" ? (
<ConfigSection title="知识库" description="选择 Agent 检索知识的范围和优先级。">
<ConfigSection>
<AddRow
value={knowledgeToAdd}
options={knowledgeOptions.filter((option) => !selectedKnowledgeIds.includes(Number(option.value)))}
@@ -703,7 +721,7 @@ export function AIAgentConfigWorkbench({
) : null}
{activeSection === "skills" ? (
<ConfigSection title="Skills" description="选择固定业务流程和多步任务能力。">
<ConfigSection>
<AddRow
value={skillToAdd}
options={skillOptions.filter((option) => !selectedSkillIds.includes(Number(option.value)))}
@@ -723,7 +741,7 @@ export function AIAgentConfigWorkbench({
) : null}
{activeSection === "tools" ? (
<ConfigSection title="MCP Tools" description="配置外部 MCP Direct Tools。内置 Graph Tool 由会话流程节点管理。">
<ConfigSection>
<div className="grid grid-cols-1 gap-3 lg:grid-cols-[220px_minmax(0,1fr)_auto]">
<OptionCombobox
value={directToolGroupToAdd}
@@ -781,7 +799,7 @@ export function AIAgentConfigWorkbench({
) : null}
{activeSection === "handoff" ? (
<ConfigSection title="转人工与兜底" description="配置无法自动完成时的接入和回复策略。">
<ConfigSection>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<FieldBlock label="转人工模式">
<OptionCombobox value={handoffMode} options={handoffModeOptions} placeholder="选择转人工模式" onChange={setHandoffMode} />
@@ -812,14 +830,76 @@ export function AIAgentConfigWorkbench({
) : null}
{activeSection === "publish" ? (
<ConfigSection title="发布状态" description="查看当前 Agent 流程发布状态。">
<div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
<StatusTile label="Agent 状态" value={agent?.statusName || "-"} />
<StatusTile label="运行模式" value={agent?.runtimeModeName || "-"} />
<StatusTile label="生效流程版本" value={agent?.workflowVersionId ? `#${agent.workflowVersionId}` : "未发布"} />
<ConfigSection>
<div className="flex flex-wrap items-center gap-x-6 gap-y-2 rounded-md border px-3 py-2 text-sm">
<div className="flex items-center gap-2">
<span className="text-muted-foreground">Agent </span>
<Badge variant="secondary">{agent?.statusName || "-"}</Badge>
</div>
<div className="flex items-center gap-2">
<span className="text-muted-foreground"></span>
<Badge variant="outline">{agent?.runtimeModeName || "-"}</Badge>
</div>
<div className="flex items-center gap-2">
<span className="text-muted-foreground"></span>
<Badge variant={agent?.workflowVersionId ? "default" : "outline"}>
{agent?.workflowVersionId ? `#${agent.workflowVersionId}` : "未发布"}
</Badge>
</div>
<div className="min-w-0 flex-1 text-xs text-muted-foreground">
稿
</div>
</div>
<div className="rounded-md border bg-muted/20 p-4 text-sm text-muted-foreground">
稿 Agent
<div className="space-y-3">
<div>
<h3 className="text-sm font-medium"></h3>
<p className="mt-1 text-xs text-muted-foreground">
</p>
</div>
<div className="overflow-hidden rounded-md border">
{workflowVersions.length > 0 ? (
<Table>
<TableHeader className="bg-muted/40">
<TableRow>
<TableHead className="w-28"></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{workflowVersions.map((version) => (
<TableRow key={version.id}>
<TableCell>
<div className="flex items-center gap-2">
<span className="font-medium">v{version.version}</span>
{agent?.workflowVersionId === version.id ? (
<Badge variant="secondary"></Badge>
) : null}
</div>
</TableCell>
<TableCell className="text-muted-foreground">
{version.publishedAt || version.createdAt || "-"}
</TableCell>
<TableCell>{version.publishedByName || "-"}</TableCell>
<TableCell>
<Badge variant={version.status === Status.Ok ? "outline" : "secondary"}>
{version.status === Status.Ok ? "启用" : "禁用"}
</Badge>
</TableCell>
<TableCell className="text-right font-mono text-xs text-muted-foreground">
{version.definitionHash ? version.definitionHash.slice(0, 8) : "-"}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
) : (
<div className="p-4 text-sm text-muted-foreground"></div>
)}
</div>
</div>
</ConfigSection>
) : null}
@@ -833,20 +913,12 @@ export function AIAgentConfigWorkbench({
}
function ConfigSection({
title,
description,
children,
}: {
title: string
description: string
children: ReactNode
}) {
return (
<section className="space-y-5">
<div>
<h2 className="text-lg font-semibold">{title}</h2>
<p className="mt-1 text-sm text-muted-foreground">{description}</p>
</div>
<div className="space-y-4">{children}</div>
</section>
)
@@ -911,12 +983,3 @@ function BadgeList({
</div>
)
}
function StatusTile({ label, value }: { label: string; value: string }) {
return (
<div className="rounded-md border bg-muted/20 p-4">
<div className="text-xs text-muted-foreground">{label}</div>
<div className="mt-2 text-sm font-medium">{value}</div>
</div>
)
}
+1 -1
View File
@@ -311,8 +311,8 @@ export default function DashboardAIAgentsPage() {
}}
title={t("aiAgent.configure")}
size="xxl"
defaultFullscreen
bodyScrollable={false}
contentClassName="top-5 left-5 h-[calc(100vh-40px)] max-h-[calc(100vh-40px)] w-[calc(100vw-40px)] max-w-[calc(100vw-40px)] translate-x-0 translate-y-0 sm:max-w-[calc(100vw-40px)]"
headerClassName="sr-only"
>
{configOpen ? (
+6
View File
@@ -815,6 +815,12 @@ export function fetchAIWorkflowNodeSpecs() {
return request<AIWorkflowNodeSpec[]>("/api/dashboard/ai-workflow/node-spec/list")
}
export function fetchAIWorkflowVersions(query?: Record<string, string | number | undefined>) {
return request<PageResult<AIWorkflowVersion>>(
`/api/dashboard/ai-workflow/version/list${toQueryString(query)}`
)
}
export function validateAIWorkflow(definition: AIWorkflowDefinition) {
return request<AIWorkflowValidationResult>("/api/dashboard/ai-agent/workflow/validate", {
method: "POST",