fix(desktop,dispatcher): 从编排执行的多 agent 图看不到「团队」tab

现象:编排里并排三个 agent(研究/撰写/审查)跑完,运行页没有团队 tab。

两处卡住,不是一处:
1) isMultiAgent 只认 coordinator: 节点。用户自己在图里并排多个 agent 也是
   团队,却被整个漏掉。改成:有协调者,或 ≥2 个 agent: 节点。
2) 就算放宽 1,deriveTeam 仍按 kind==="agent" 挑工位——而两条产生 agent 的
   路径 kind 并不一致:协调者派发的专家是 kind=agent,图里的 agent 节点是
   kind=model。改成按节点名前缀(agent:/tool:)判,这本来就是后端一直遵守的
   约定;顺带天然把 retriever:/map:/render: 这些同为 kind=tool 的节点挡在
   工位之外(之前它们会混进来当工位)。

连带修一个更要命的:runAgent 把轨迹标签写死成"模型流式推理"、runReactAgent
写死成"ReAct 智能体(自主调工具)",用户在编排里给节点起的名字(研究 Agent /
撰写 Agent / 审查 Agent)整个丢了。后果不止办公室:执行轨迹里三行同名,根本
分不出谁是谁;团队视图只能退回节点 ID,工位显示成 r/w/rev。
改成一律 labelOf(n, 兜底) 由调用方传入,+2 单测钉住。

另:没有协调者时不再凭空画一个"协调者"小人(白板改挂「任务产出」),也不演
递简报那一程(没人可递),✓ 气泡改为收工即冒。

注意:已存的历史轨迹是落库的,仍是旧标签;只有新跑的任务才有节点名。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-15 17:18:52 +08:00
parent 02608bb6a4
commit c2811e79a3
10 changed files with 188 additions and 51 deletions
@@ -66,7 +66,7 @@ func (o *Orchestrator) execComposeGraph(ctx context.Context, t *contract.Task, t
tr.info("task", "system", "无结构化图", "按单轮对话执行(compose")
b.profile = o.fetchMemory(ctx, b.uid, b.query)
b.history = o.fetchHistory(ctx, b.sid)
o.runComposeConversation(ctx, t.ID, b, plan.System, tr, "agent")
o.runComposeConversation(ctx, t.ID, b, plan.System, tr, "agent", "模型流式推理")
return b.answer, refsOf(b), b.fatalErr // 模型失败 → 上抛判 failed(对齐 graph.go
}
@@ -211,7 +211,7 @@ func (o *Orchestrator) execComposeGraph(ctx context.Context, t *contract.Task, t
if cerr != nil {
// 编译失败(罕见)→ 降级为单轮对话兜底(自研 graph.go 已退役,不再回退)。
tr.info("task", "system", "compose 编译失败", "降级单轮对话:"+cerr.Error())
o.runComposeConversation(ctx, t.ID, b, plan.System, tr, "agent")
o.runComposeConversation(ctx, t.ID, b, plan.System, tr, "agent", "模型流式推理")
return b.answer, refsOf(b), b.fatalErr
}
// checkpoint id = task id:审批中断时 compose 据此把整图状态(含 board)落进 store。
@@ -253,7 +253,7 @@ func (o *Orchestrator) execComposeGraph(ctx context.Context, t *contract.Task, t
// 图里无 agent 节点(纯工具/检索图)也要出一段答复。
if fb.answer == "" {
o.runComposeConversation(ctx, t.ID, fb, plan.System, tr, "agent")
o.runComposeConversation(ctx, t.ID, fb, plan.System, tr, "agent", "模型流式推理")
if fb.fatalErr != nil { // 兜底对话也可能触预算顶 / 模型失败
return fb.answer, nil, fb.fatalErr
}
@@ -289,7 +289,7 @@ func (o *Orchestrator) execDSLNode(ctx context.Context, t *contract.Task, n dsl.
if cbool(n.Config, "autonomous") {
o.runReactAgent(ctx, t.ID, b, sys, n, tr, "agent:"+n.ID)
} else {
o.runAgent(ctx, t.ID, b, sys, tr, "agent:"+n.ID)
o.runAgent(ctx, t.ID, b, sys, tr, "agent:"+n.ID, labelOf(n, "智能体"))
}
case "coordinator": // 多智能体协调:orchestrator 自主把子任务派给专家(agent-as-tool)再综合
o.runCoordinator(ctx, t.ID, b, firstNonEmpty(cstr(n.Config, "system"), plan.System), n, tr, "coordinator:"+n.ID)