package coordinator import ( "context" "fmt" "strings" "chat-agent-system/internal/contracts/vocabulary" "chat-agent-system/internal/intent" ) // handleDocGovCommentAdd 解析门 → 批注矩阵剪枝 → CONFIRMATION 卡(含内容预览) func (e *CoordinatorEngine) handleDocGovCommentAdd(ctx context.Context, cand *intent.CandidateIntent, userCtx *UserProjectContext) (*CoordinationResult, error) { doc, gate := e.resolveTargetDocGate(ctx, cand, userCtx) if gate != nil { return gate, nil } content := strings.TrimSpace(cand.FilledSlots[intent.SlotCommentContent]) section := strings.TrimSpace(cand.FilledSlots[intent.SlotTargetSection]) cType := strings.TrimSpace(cand.FilledSlots[intent.SlotCommentType]) if cType == "" { cType = "suggestion" } if content == "" { return &CoordinationResult{ Status: StatusClarificationRequired, Intent: cand.Intent, Branch: cand.Branch, ClarificationPrompt: "请补充批注内容后再确认添加。", NaturalReply: "已定位文档,但缺少批注正文。请说明要添加的意见内容。", UpdatedContext: userCtx, }, nil } role := effectiveDocRole(userCtx) if userCtx != nil && userCtx.ToSnapshot() != nil && userCtx.ToSnapshot().UserDocRole != "" { role = userCtx.ToSnapshot().UserDocRole } state := doc.State if state == "" && userCtx != nil && userCtx.ToSnapshot() != nil { state = vocabulary.DocumentState(userCtx.ToSnapshot().DocLifecycleState) } if state != "" && role != "" && !commentRoleAllowed(role, state) { return &CoordinationResult{ Status: StatusRejected, Intent: cand.Intent, Branch: cand.Branch, RejectReason: "COMMENT_MATRIX_DENIED", NaturalReply: fmt.Sprintf("按批注矩阵,角色「%s」在「%s」阶段不可添加批注。", role, state), UpdatedContext: userCtx, }, nil } title := displayDocTitle(doc) preview := content if section != "" { preview = fmt.Sprintf("[%s] %s", section, content) } card, exp := buildConfirmCard( "添加受控文档批注确认", doc.DocID, title, section, preview, "确认后将写入文档批注;服务端会按角色×阶段矩阵二次校验。", "confirm_comment_add", "确认添加批注", map[string]string{ "role": role, "comment_content": content, "comment_type": cType, "target_section": section, }, ) userCtx.applyCard(card) userCtx.applyPending(exp) reply := fmt.Sprintf("已为《%s》起草批注确认单。预览:%s。请确认或回复「确认」。", title, preview) return &CoordinationResult{ Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch, NaturalReply: reply, InteractiveCard: card, NextExpectation: exp, UpdatedContext: userCtx, }, nil } // handleDocGovCommentResolve 解析门 → CONFIRMATION 卡 → PendingAction func (e *CoordinatorEngine) handleDocGovCommentResolve(ctx context.Context, cand *intent.CandidateIntent, userCtx *UserProjectContext) (*CoordinationResult, error) { doc, gate := e.resolveTargetDocGate(ctx, cand, userCtx) if gate != nil { return gate, nil } section := strings.TrimSpace(cand.FilledSlots[intent.SlotTargetSection]) role := effectiveDocRole(userCtx) title := displayDocTitle(doc) proposed := "将匹配的未解决批注标记为已处理" if section != "" { proposed = fmt.Sprintf("将章节「%s」下未解决批注标记为已处理", section) } card, exp := buildConfirmCard( "解决受控文档批注确认", doc.DocID, title, section, proposed, "确认后由服务端按角色权限二次校验并更新批注状态。", "confirm_comment_resolve", "确认解决批注", map[string]string{"role": role, "target_section": section}, ) userCtx.applyCard(card) userCtx.applyPending(exp) return &CoordinationResult{ Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch, NaturalReply: fmt.Sprintf("已为《%s》起草解决批注确认单。请确认后执行。", title), InteractiveCard: card, NextExpectation: exp, UpdatedContext: userCtx, }, nil }