Files
weichen 3d6dcc3ae5 feat(web): 用小队子页面展示思考与工具过程
气泡只聚合过程摘要并链到 hash 子页面;成员编制来自只读 squad 端点,思考与工具默认折叠。
2026-09-28 10:30:53 +00:00

61 lines
1.8 KiB
Go

package squad
import (
"encoding/json"
"os"
"path/filepath"
)
// SquadMemberView 是子页面左栏的只读编制投影(不含模型名与工具权限)。
type SquadMemberView struct {
Role string `json:"role"`
Name string `json:"name"`
Responsibilities []string `json:"responsibilities"`
Source string `json:"source,omitempty"`
}
// SquadProjection GET /tasks/runs/{id}/squad 的响应体。
type SquadProjection struct {
Members []SquadMemberView `json:"members"`
TaskKey string `json:"task_key"`
Title string `json:"title"`
}
// ReadSquadProjection 读取工作区 squad.json(及可选 workspace.json 标题)。
// 缺少 squad.json 时返回错误,由调用方决定 404。
func ReadSquadProjection(workDir string) (SquadProjection, error) {
data, err := os.ReadFile(filepath.Join(workDir, "squad.json"))
if err != nil {
return SquadProjection{}, err
}
var cfg SquadConfig
if err := json.Unmarshal(data, &cfg); err != nil {
return SquadProjection{}, err
}
members := make([]SquadMemberView, 0, len(cfg.Agents))
for _, agent := range cfg.Agents {
resp := agent.Responsibilities
if resp == nil {
resp = []string{}
}
members = append(members, SquadMemberView{
Role: agent.Role,
Name: agent.Name,
Responsibilities: resp,
Source: string(agent.Source),
})
}
title := cfg.SquadName
taskKey := ""
if metaRaw, err := os.ReadFile(filepath.Join(workDir, "workspace.json")); err == nil {
var meta WorkspaceMetadata
if json.Unmarshal(metaRaw, &meta) == nil {
if meta.StageTitle != "" {
title = meta.StageTitle
}
taskKey = meta.TaskKey
}
}
return SquadProjection{Members: members, TaskKey: taskKey, Title: title}, nil
}