From b49b87b683788108fe09b801c09cdd4d637f17aa Mon Sep 17 00:00:00 2001 From: SaladDay <1203511142@qq.com> Date: Sun, 8 Nov 2026 10:36:34 +0000 Subject: [PATCH] Show each Agent's parts on its Parsar card --- example/parsar/src/Agents.tsx | 113 ++++++++++++++++++++++--- example/parsar/src/ExecutionFields.tsx | 3 - example/parsar/src/lib/en.json | 4 +- example/parsar/tests/workflow.spec.ts | 3 + 4 files changed, 107 insertions(+), 16 deletions(-) diff --git a/example/parsar/src/Agents.tsx b/example/parsar/src/Agents.tsx index f5324c0ae..21b3997ab 100644 --- a/example/parsar/src/Agents.tsx +++ b/example/parsar/src/Agents.tsx @@ -1,13 +1,18 @@ import { tr } from "./lib/i18n"; import { useState } from "react"; -import { Plus, Search, Send, Server } from "lucide-react"; +import { Blocks, Plug, Plus, Search, Send, Server } from "lucide-react"; import { useAgents, useFeishuBots, + useMCPs, useModels, useRuntimes, type AgentProfile, + type FeishuBot, + type RuntimeProfile, } from "./lib/product"; +import { useCapabilities } from "./Capabilities"; +import { useSkills } from "./Skills"; import { engineSummary } from "./ExecutionFields"; import { Button } from "./components/ui/button"; import { Input } from "./components/ui/input"; @@ -42,7 +47,12 @@ export function Agents() { const agents = useAgents(), models = useModels(), runtimes = useRuntimes(), - bots = useFeishuBots(); + bots = useFeishuBots(), + skills = useSkills(), + mcps = useMCPs(), + capabilities = useCapabilities(); + const names = (rows: { id: string; name: string }[] = [], ids: string[] = []) => + ids.flatMap((id) => rows.find((row) => row.id === id)?.name || []); const [search, setSearch] = useState(""); const rows = (agents.data || []).filter((agent) => `${agent.name} ${agent.description || ""}` @@ -93,8 +103,18 @@ export function Agents() { key={agent.id} agent={agent} engine={engineSummary(agent, models.data)} - runtime={runtimes.data?.find((r) => r.id === agent.runtime_id)?.name} - bot={bots.data?.find((b) => b.agent_id === agent.id)?.name} + runtime={runtimes.data?.find((r) => r.id === agent.runtime_id)} + bot={bots.data?.find((b) => b.agent_id === agent.id)} + skills={names(skills.data, agent.skill_ids)} + capabilities={[ + ...(agent.web_search && agent.web_search !== "disabled" ? [tr("网页搜索")] : []), + ...(agent.ask_user ? [tr("向用户提问")] : []), + ...names(mcps.data, agent.mcp_ids), + ...names( + capabilities.data?.filter((row) => row.kind !== "prompt"), + agent.capability_ids, + ), + ]} /> ))} @@ -104,18 +124,46 @@ export function Agents() { ); } +// One line of the card: which bot, template, Skills or capabilities the Agent is assembled from. +function Part({ + icon: Icon, + label, + children, +}: { + icon: typeof Server; + label: string; + children: React.ReactNode; +}) { + return ( +
+ + + {label} + +
{children}
+
+ ); +} + +const shownSkills = 8; + function AgentCard({ agent, engine, runtime, bot, + skills, + capabilities, }: { agent: AgentProfile; engine: string; - runtime?: string; - bot?: string; + runtime?: RuntimeProfile; + bot?: FeishuBot; + skills: string[]; + capabilities: string[]; }) { const disabled = agent.enabled === false; + const packages = [...(runtime?.packages?.npm || []), ...(runtime?.packages?.python || [])]; return (
@@ -135,14 +183,55 @@ function AgentCard({
{disabled && {tr("已停用")}} -

+

{agent.description || agent.instructions || tr("暂无描述")}

-
- - {runtime || tr("未选择环境")} - - {bot && {bot}} +
+ + {bot ? ( + + {bot.name} + {bot.health?.state === "connected" && ( + + )} + + ) : ( + {tr("未绑定")} + )} + + + {runtime ? ( + <> + {runtime.name} + {packages.map((name) => ( + {name} + ))} + + ) : ( + {tr("未选择环境")} + )} + + + {skills.length ? ( + <> + {skills.slice(0, shownSkills).map((name) => ( + {name} + ))} + {skills.length > shownSkills && ( + +{skills.length - shownSkills} + )} + + ) : ( + {tr("无")} + )} + + + {capabilities.length ? ( + capabilities.map((name) => {name}) + ) : ( + {tr("无")} + )} +