package squad import ( "fmt" "os" "strings" ) const rdevDHFAccept = "模板写满;结论先行;追溯表必填;缺项标「待确认」;不编造数据/签字/附件" func rdevModel() string { if v := strings.TrimSpace(os.Getenv("SQUAD_MODEL_ID")); v != "" { return v } if v := strings.TrimSpace(os.Getenv("MINIMAX_MODEL_ID")); v != "" { return v } return "MiniMax-M3" } func rdevComplexityTier(fields map[string]string) string { if fields == nil { return "" } switch strings.ToLower(strings.TrimSpace(fields["complexity_tier"])) { case "high", "medium", "low": return strings.ToLower(strings.TrimSpace(fields["complexity_tier"])) default: return "" } } func rdevSquadAgents(taskKey, tier string) []AgentSpec { if ov, ok := rdevResolvedOverride(taskKey, tier); ok { return rdevAgentsFromOverride(ov) } meta, _ := LookupRDevTask(taskKey) agents := []AgentSpec{ { Role: "organizer", Name: "材料整理专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"材料事实抽取", "适用性与缺口识别", "字段回填"}, ForbiddenActions: []string{"严禁编造试验数据", "严禁伪造签字"}, }, } switch meta.Kind { case RDevKindReviewMinutes: agents = append(agents, AgentSpec{ Role: "writer", Name: "文档撰写专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"按评审记录模板成文", "问题-决议-行动项闭环"}, }, rdevLeaderAgent(), ) case RDevKindUploadIndex: agents = append(agents, AgentSpec{ Role: "engineer", Name: "技术专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"附件索引完整性", "缺失影响分析"}, }, AgentSpec{ Role: "writer", Name: "文档撰写专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"按附件清单模板成文", "标明待上传项"}, }, rdevLeaderAgent(), ) default: agents = append(agents, AgentSpec{ Role: "engineer", Name: "技术专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"技术内容与追溯", "设计控制论证"}, }, ) if RDevNeedsRegulatoryAt(taskKey, tier) { agents = append(agents, AgentSpec{ Role: "regulatory", Name: "法规专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"法规/标准适用性", "软件与风险管理合规要点"}, }) } agents = append(agents, AgentSpec{ Role: "writer", Name: "文档撰写专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"按 RD 模板成文", "结论先行与待确认清单"}, }, rdevLeaderAgent(), ) } return agents } func rdevLeaderAgent() AgentSpec { return AgentSpec{ Role: "leader", Name: "研发设计控制负责人", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", InstructionsFile: "configs/agents/rdev_leader.md", Responsibilities: []string{"DHF 完整性终审", "不适用理由审核", "禁止编造检查"}, ForbiddenActions: []string{"严禁代签", "严禁伪造附件内容"}, } } func rdevWorkflowSteps(taskKey, tier string) []StepSpec { meta, ok := LookupRDevTask(taskKey) kind := RDevKindDocument title := taskKey if ok { kind = meta.Kind title = meta.Title } if ov, found := rdevResolvedOverride(taskKey, tier); found { return rdevAttachStageHint(taskKey, rdevStepsFromOverride(ov)) } switch kind { case RDevKindReviewMinutes: return rdevAttachStageHint(taskKey, []StepSpec{ { ID: "step_01_organize", Role: "organizer", Title: "整理评审输入与议题", SubWorkspace: "tasks/01_organize", Mode: "execute", Accept: []string{"汇总上游批准文档要点", "列出待评审议题与缺口", rdevDHFAccept}, }, { ID: "step_02_draft", Role: "writer", Title: "撰写评审记录", SubWorkspace: "tasks/02_draft", Mode: "execute", Needs: []string{"tasks/01_organize/output.md"}, Accept: []string{"按模板写满评审记录", "问题-决议-行动项可追溯", rdevDHFAccept}, }, { ID: "step_03_review", Role: "leader", Title: "研发设计控制终审", SubWorkspace: "tasks/03_review", Mode: "execute", Needs: []string{"tasks/02_draft/output.md"}, Accept: []string{"完整性与粒度达标", "无编造签字/数据", rdevDHFAccept}, }, }) case RDevKindUploadIndex: return rdevAttachStageHint(taskKey, []StepSpec{ { ID: "step_01_organize", Role: "organizer", Title: "整理附件材料线索", SubWorkspace: "tasks/01_organize", Mode: "execute", Accept: []string{"列出已知附件与缺失项", rdevDHFAccept}, }, { ID: "step_02_engineer", Role: "engineer", Title: "完善附件索引与影响分析", SubWorkspace: "tasks/02_engineer", Mode: "execute", Needs: []string{"tasks/01_organize/output.md"}, Accept: []string{"索引表完整", "缺失影响已说明", rdevDHFAccept}, }, { ID: "step_03_draft", Role: "writer", Title: "撰写附件清单", SubWorkspace: "tasks/03_draft", Mode: "execute", Needs: []string{"tasks/02_engineer/output.md"}, Accept: []string{"按 upload_index 模板成文", "禁止伪造附件正文", rdevDHFAccept}, }, { ID: "step_04_review", Role: "leader", Title: "研发设计控制终审", SubWorkspace: "tasks/04_review", Mode: "execute", Needs: []string{"tasks/03_draft/output.md"}, Accept: []string{"索引与待上传结论一致", rdevDHFAccept}, }, }) default: return rdevAttachStageHint(taskKey, rdevDocumentSteps(taskKey, title, tier)) } } func rdevDocumentSteps(taskKey, title, tier string) []StepSpec { steps := []StepSpec{ { ID: "step_01_organize", Role: "organizer", Title: "抽取材料事实并回填", SubWorkspace: "tasks/01_organize", Mode: "execute", Accept: []string{"facts/gaps/implications 入黑板", "适用性字段回填", rdevDHFAccept}, }, { ID: "step_02_engineer", Role: "engineer", Title: "技术内容与追溯编制", SubWorkspace: "tasks/02_engineer", Mode: "execute", Needs: []string{"tasks/01_organize/output.md"}, Accept: []string{"技术论证完整", "追溯表可填则填", rdevDHFAccept}, }, } draftNeeds := "tasks/02_engineer/output.md" if RDevNeedsRegulatoryAt(taskKey, tier) { steps = append(steps, StepSpec{ ID: "step_03_regulatory", Role: "regulatory", Title: "法规与风险合规要点", SubWorkspace: "tasks/03_regulatory", Mode: "execute", Needs: []string{"tasks/02_engineer/output.md"}, Accept: []string{"法规适用性明确", "风险类引用可追溯", rdevDHFAccept}, }) draftNeeds = "tasks/03_regulatory/output.md" steps = append(steps, StepSpec{ ID: "step_04_draft", Role: "writer", Title: "撰写《" + title + "》", SubWorkspace: "tasks/04_draft", Mode: "execute", Needs: []string{draftNeeds}, Accept: []string{"严格按 rd_ 模板成文", "结论先行", rdevDHFAccept}, }, StepSpec{ ID: "step_05_review", Role: "leader", Title: "研发设计控制终审", SubWorkspace: "tasks/05_review", Mode: "execute", Needs: []string{"tasks/04_draft/output.md"}, Accept: []string{"DHF 粒度达标", "无编造", rdevDHFAccept}, }, ) return steps } steps = append(steps, StepSpec{ ID: "step_03_draft", Role: "writer", Title: "撰写《" + title + "》", SubWorkspace: "tasks/03_draft", Mode: "execute", Needs: []string{draftNeeds}, Accept: []string{"严格按 rd_ 模板成文", "结论先行", rdevDHFAccept}, }, StepSpec{ ID: "step_04_review", Role: "leader", Title: "研发设计控制终审", SubWorkspace: "tasks/04_review", Mode: "execute", Needs: []string{"tasks/03_draft/output.md"}, Accept: []string{"DHF 粒度达标", "无编造", rdevDHFAccept}, }, ) return steps } func rdevIncludeConditionalRegulatory(taskKey, tier string) bool { switch strings.ToLower(strings.TrimSpace(tier)) { case "medium", "low": return false case "high": return true default: return RDevNeedsRegulatory(taskKey) } } func rdevResolvedOverride(taskKey, tier string) ([]rdevOverrideStep, bool) { raw, ok := rdevStageOverrides[taskKey] if !ok { return nil, false } out := make([]rdevOverrideStep, 0, len(raw)) for _, step := range raw { if step.WhenHigh && !rdevIncludeConditionalRegulatory(taskKey, tier) { continue } out = append(out, step) } return out, true } func rdevAgentsFromOverride(steps []rdevOverrideStep) []AgentSpec { seen := map[string]bool{} var agents []AgentSpec for _, step := range steps { if seen[step.Role] { continue } seen[step.Role] = true agents = append(agents, rdevAgentForRole(step.Role)) } return agents } func rdevAgentForRole(role string) AgentSpec { switch role { case "writer": return AgentSpec{ Role: "writer", Name: "文档撰写专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"按 RD 模板成文", "结论先行与待确认清单"}, } case "engineer": return AgentSpec{ Role: "engineer", Name: "技术专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"技术内容与追溯", "设计控制论证"}, } case "regulatory": return AgentSpec{ Role: "regulatory", Name: "法规专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"法规/标准适用性", "软件与风险管理合规要点"}, } case "searcher": return AgentSpec{ Role: "searcher", Name: "资料检索专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"公开资料检索", "出处与日期标注"}, ForbiddenActions: []string{"严禁编造URL与标准号"}, } case "leader": return rdevLeaderAgent() default: return AgentSpec{ Role: "organizer", Name: "材料整理专员", Model: rdevModel(), Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"材料事实抽取", "适用性与缺口识别", "字段回填"}, ForbiddenActions: []string{"严禁编造试验数据", "严禁伪造签字"}, } } } func rdevStepsFromOverride(steps []rdevOverrideStep) []StepSpec { out := make([]StepSpec, 0, len(steps)) var parallelOutputs []string prev := "" for i, step := range steps { id := fmt.Sprintf("step_%02d_%s", i+1, step.Role) sub := fmt.Sprintf("tasks/%02d_%s", i+1, step.Role) spec := StepSpec{ ID: id, Role: step.Role, Title: step.Title, SubWorkspace: sub, Mode: "execute", Parallel: step.Parallel, Accept: []string{rdevDHFAccept}, } if step.Delegate { spec.Accept = append([]string{"可委托检索,未命中须写检索局限"}, spec.Accept...) } if i > 0 { if step.Parallel { if prev != "" { spec.Needs = []string{prev} } } else if len(parallelOutputs) > 0 { spec.Needs = append([]string(nil), parallelOutputs...) parallelOutputs = nil } else if prev != "" { spec.Needs = []string{prev} } } out = append(out, spec) file := sub + "/output.md" if step.Parallel { parallelOutputs = append(parallelOutputs, file) } else { prev = file parallelOutputs = nil } } return out } func rdevAttachStageHint(taskKey string, steps []StepSpec) []StepSpec { meta, ok := LookupRDevTask(taskKey) if !ok { return steps } for i := range steps { if steps[i].Role == "writer" && meta.Hint != "" { steps[i].Accept = append(steps[i].Accept, meta.Hint) } if steps[i].Role == "organizer" && meta.SkipHint != "" { steps[i].Accept = append(steps[i].Accept, meta.SkipHint) } } return steps }