From cb6eec5614e9ff7543b6a3c73cd0cf45d1c5dae2 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Mon, 29 Jun 2026 17:14:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(desktop):=20T0.2=20=E5=A4=9A=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E4=BD=93=E8=BF=9B=20Studio=20=E2=80=94=E2=80=94=20coo?= =?UTF-8?q?rdinator=20=E8=8A=82=E7=82=B9=20+=20=E4=B8=93=E5=AE=B6=E5=8D=A1?= =?UTF-8?q?=E7=89=87=20+=20=E6=B4=BE=E5=8F=91=E5=8F=AF=E8=A7=82=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 把已通的多智能体后端(MULTI_AGENT.md)接上 UI,用户可在画布拖出协调者图。 - nodeCatalog: 新增 `coordinator`「多智能体协调」节点(indigo) + 新字段类型 `agentList` + Specialist 接口({name,use,system,tools}),与后端 parseSpecialists 对齐。 - Inspector: AgentListField —— 可增删的子智能体卡片(名/用途/系统提示词/工具逗号分隔)。 - dsl 校验: agentList 需 ≥1 个有名字的专家、名字不重复。 - RunsView: 「工具调用」面板纳入专家派发(kind=agent),改名「工具/专家」,专家项 用 Users 图标 + indigo「专家」徽标区分(此前只筛 kind=tool,漏掉多智能体派发)。 - 导出: agents 数组经 exportDsl 原样透传进 DSL → 后端 parseSpecialists 直接消费。 tsc + vitest(19) 绿;UI 同款结构 DSL 后端可跑(协调链路 live 已验)。 DEPTH_ROADMAP T0.2 ✅,T0 激活 2/2 完成。 Co-Authored-By: Claude Opus 4.8 --- DEPTH_ROADMAP.md | 16 +++--- sundynix-desktop/frontend/src/lib/dsl.ts | 10 ++++ .../frontend/src/studio/Inspector.tsx | 50 ++++++++++++++++++- .../frontend/src/studio/nodeCatalog.ts | 23 ++++++++- .../frontend/src/views/RunsView.tsx | 48 ++++++++++-------- 5 files changed, 116 insertions(+), 31 deletions(-) diff --git a/DEPTH_ROADMAP.md b/DEPTH_ROADMAP.md index fcf3b4e..bf4b7cc 100644 --- a/DEPTH_ROADMAP.md +++ b/DEPTH_ROADMAP.md @@ -25,13 +25,15 @@ - **验收 ✅ live(deepseek)**:跑题→0.40 poor→**触发纠偏(0.40→0.55)**;截断→0.55 warn;好答案→1.00 ok。 校准前这三个全是 1.00→ok,恒温器从没触发。 -### [ ] T0.2 多智能体进 Studio(多智能体 v2) +### [x] T0.2 多智能体进 Studio(多智能体 v2)✅ 现状:coordinator 后端已通(见 MULTI_AGENT.md),但画布拖不出。 -- [ ] nodeCatalog 加 `coordinator` 节点 + 新 `agentList` 字段(子智能体卡片:名/用途/系统提示词/工具多选) -- [ ] StudioView 渲染+编辑 agentList,校验(≥1 专家、名唯一) -- [ ] 运行轨迹:专家派发渲染成可展开子节点(显示 brief + 精炼结论) -- [ ] preview/真机验证:UI 搭两专家协调任务跑通 -- 验收:用户能在 Studio 拖出协调者图并运行,轨迹看到并行派发 + 综合。 +- [x] nodeCatalog 加 `coordinator` 节点(「多智能体协调」,indigo)+ 新 `agentList` 字段类型 + Specialist 接口 +- [x] Inspector `AgentListField`:可增删的专家卡片(名/用途/系统提示词/工具逗号分隔) +- [x] dsl 校验:agentList 需 ≥1 个有名字的专家 + 名字不重复 +- [x] 运行轨迹「工具调用」面板纳入专家派发(kind=agent)→ 改名「工具/专家」,专家项 indigo 标识 +- [x] 后端验证:UI 同款 DSL 结构提交可跑(agents 数组经 exportDsl 透传 → parseSpecialists) +- 验收 ✅:Studio 左栏出现「多智能体协调」节点,检查器配专家卡片,导出 DSL 对齐后端; + 轨迹/工具面板能看到专家派发。(真机由用户在 wails 窗口确认) --- @@ -89,7 +91,7 @@ | Tier | 完成 / 总 | |---|---| -| T0 激活 | 1 / 2 | +| T0 激活 | 2 / 2 ✅ | | T1 收口 | 0 / 2 | | T2 深化 | 0 / 3 | | T3 硬化 ⏸ | 0 / 5 | diff --git a/sundynix-desktop/frontend/src/lib/dsl.ts b/sundynix-desktop/frontend/src/lib/dsl.ts index 6667044..99ff23f 100644 --- a/sundynix-desktop/frontend/src/lib/dsl.ts +++ b/sundynix-desktop/frontend/src/lib/dsl.ts @@ -52,6 +52,16 @@ export function validate(nodes: Node[], edges: Edge[]): Issue[] { .filter((f) => f.required) .forEach((f) => { const v = d.config?.[f.key]; + if (f.type === "agentList") { + const arr = Array.isArray(v) ? (v as Array<{ name?: string }>) : []; + const names = arr.map((s) => s?.name?.trim()).filter(Boolean) as string[]; + if (names.length === 0) { + issues.push({ level: "warn", msg: `节点「${d.label || k.label}」至少需要一个有名字的专家` }); + } else if (new Set(names).size !== names.length) { + issues.push({ level: "warn", msg: `节点「${d.label || k.label}」专家名有重复` }); + } + return; + } if (v === undefined || v === "" || String(v).startsWith("(未")) { issues.push({ level: "warn", msg: `节点「${d.label || k.label}」缺必填项:${f.label}` }); } diff --git a/sundynix-desktop/frontend/src/studio/Inspector.tsx b/sundynix-desktop/frontend/src/studio/Inspector.tsx index 2763279..327b9b4 100644 --- a/sundynix-desktop/frontend/src/studio/Inspector.tsx +++ b/sundynix-desktop/frontend/src/studio/Inspector.tsx @@ -1,8 +1,52 @@ import type { Node } from "@xyflow/react"; -import { NODE_KINDS } from "./nodeCatalog"; +import { NODE_KINDS, type Specialist } from "./nodeCatalog"; const inputCls = "mt-1 w-full rounded-md border border-line bg-ink-800 px-2 py-1 text-sm text-slate-200 focus:border-violet-500/60 focus:outline-none"; +const cardCls = + "w-full rounded border border-line bg-ink-800 px-2 py-1 text-[12px] text-slate-200 placeholder:text-slate-600 focus:border-indigo-500/60 focus:outline-none"; + +// AgentListField:多智能体协调节点的「子智能体(专家)」配置 —— 可增删的专家卡片。 +// 每张卡片对齐后端 parseSpecialists 的 {name, use, system, tools}。 +function AgentListField({ value, onChange }: { value: Specialist[]; onChange: (next: Specialist[]) => void }) { + const list = Array.isArray(value) ? value : []; + const update = (i: number, patch: Partial) => onChange(list.map((s, idx) => (idx === i ? { ...s, ...patch } : s))); + const add = () => onChange([...list, { name: "", use: "", system: "", tools: [] }]); + const remove = (i: number) => onChange(list.filter((_, idx) => idx !== i)); + return ( +
+ {list.map((s, i) => ( +
+
+ update(i, { name: e.target.value })} /> + +
+ update(i, { use: e.target.value })} /> +