diff --git a/frontend-web/src/roundtable-planning/components/AgentDetailSheet.tsx b/frontend-web/src/roundtable-planning/components/AgentDetailSheet.tsx new file mode 100644 index 00000000..45165f8f --- /dev/null +++ b/frontend-web/src/roundtable-planning/components/AgentDetailSheet.tsx @@ -0,0 +1,151 @@ +/** + * 智能体详情抽屉(右侧 Sheet)。 + * + * 业务链条配置页:左栏候选卡片点击卡片本体、右栏席位点「查看详情」都打开这个抽屉, + * 展示该智能体的详情(与「智能体」详情页展示的内容差不多):名称 / 模型 / 描述 / + * 标签 / 技能 + 工具组 / 人设(SOUL.md)。 + * + * 详情按需拉取:`useAgent(open ? agentId : null)` —— 抽屉打开时才请求 `GET /api/agents/{id}` + * (该接口才返回 soul),关闭不请求。字段渲染对齐 `components/workspace/agents/agent-card.tsx`。 + */ +import { Bot, Globe, Loader2, Lock } from "lucide-react"; + +import { Badge } from "@/components/ui/badge"; +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, +} from "@/components/ui/sheet"; +import { TagChipList } from "@/components/workspace/tags/tag-chip"; +import { useAgent } from "@/core/agents"; +import { desensitize } from "@/lib/desensitize"; + +export function AgentDetailSheet({ + agentId, + /** 卡片/席位上的名称快照,详情还没拉回来时先用它占位。 */ + fallbackName, + open, + onOpenChange, +}: { + agentId: string | null; + fallbackName?: string; + open: boolean; + onOpenChange: (open: boolean) => void; +}) { + // 抽屉打开时才拉详情(含 soul);关闭传 null 让 useAgent 不发请求。 + const { agent, isLoading } = useAgent(open ? agentId : null); + const name = agent?.name || fallbackName || agentId || ""; + const skillItems = agent?.skills ?? []; + const toolGroups = agent?.tool_groups ?? []; + const hasSkillsOrTools = skillItems.length > 0 || toolGroups.length > 0; + + return ( + + + + + + + + {name} + {agent?.model && ( + + {desensitize(agent.model)} + + )} + + 智能体详情 + + +
+ {isLoading && !agent ? ( +
+ + 正在加载详情… +
+ ) : !agent ? ( +
+ 未找到该智能体的详情(可能已被删除)。 +
+ ) : ( + <> + {/* 状态徽标 */} +
+ {agent.builtin && ( + 内置 + )} + {agent.published && ( + + + 已发布 + + )} + {agent.is_private && ( + + + 私密 + + )} +
+ + {/* 描述 */} +
+

+ 描述 +

+

+ {agent.description?.trim() || "(无描述)"} +

+
+ + {/* 标签 */} + {agent.tags && agent.tags.length > 0 && ( +
+

+ 标签 +

+ +
+ )} + + {/* 技能 / 工具组 */} + {hasSkillsOrTools && ( +
+

+ 技能与工具 +

+
+ {toolGroups.map((group) => ( + + {desensitize(group)} + + ))} + {skillItems.map((skill) => ( + + {desensitize(skill)} + + ))} +
+
+ )} + + {/* 人设(SOUL.md) */} + {agent.soul?.trim() && ( +
+

+ 人设 +

+
+                    {agent.soul}
+                  
+
+ )} + + )} +
+
+
+ ); +} diff --git a/frontend-web/src/roundtable-planning/pages/BusinessChainEditorPage.tsx b/frontend-web/src/roundtable-planning/pages/BusinessChainEditorPage.tsx index f92e329e..09ac5560 100644 --- a/frontend-web/src/roundtable-planning/pages/BusinessChainEditorPage.tsx +++ b/frontend-web/src/roundtable-planning/pages/BusinessChainEditorPage.tsx @@ -30,6 +30,7 @@ import { GitBranch, Globe, GripVertical, + Info, Layers, Loader2, Network, @@ -110,6 +111,7 @@ import { } from "@/roundtable-planning/lib/chain-stages"; import { getAvatarTypeFor } from "@/roundtable-planning/lib/roundtable-constants"; import { DagFlowChart } from "@/roundtable-planning/components/DagFlowChart"; +import { AgentDetailSheet } from "@/roundtable-planning/components/AgentDetailSheet"; const POOL_PREFIX = "pool::"; const SEAT_PREFIX = "seat::"; @@ -155,6 +157,11 @@ export default function BusinessChainEditorPage() { const [activeDrag, setActiveDrag] = useState(null); const [dropdownOpen, setDropdownOpen] = useState(false); const [flowOpen, setFlowOpen] = useState(false); + // 详情抽屉:左栏点卡片本体、右栏点「查看详情」都打开它,展示该智能体详情。 + const [detailAgent, setDetailAgent] = useState<{ id: string; name?: string } | null>(null); + const showDetail = useCallback((id: string, name?: string) => { + setDetailAgent({ id, name }); + }, []); const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 5 } }), @@ -763,7 +770,7 @@ export default function BusinessChainEditorPage() { {pool.length} - 拖到右侧 / 点击加入 + 拖手柄到右侧 / 点卡片看详情
@@ -794,6 +801,7 @@ export default function BusinessChainEditorPage() { agent={a} inChain={seatIdSet.has(a.agent_id)} onAdd={() => addAgentAsNewStage(a.agent_id)} + onShowDetail={() => showDetail(a.agent_id, a.name)} /> )) )} @@ -813,6 +821,7 @@ export default function BusinessChainEditorPage() { onMergeSeat={mergeSeatToStage} onSplitSeat={splitSeat} onStageGoalChange={setGoal} + onSeatDetail={showDetail} /> @@ -873,6 +882,16 @@ export default function BusinessChainEditorPage() { )} + {/* 智能体详情抽屉(左栏卡片 / 右栏席位共用) */} + { + if (!o) setDetailAgent(null); + }} + /> + {/* 页脚 */}