package chat import ( "context" "fmt" "strconv" "strings" "time" "chat-agent-system/internal/bizdev" "chat-agent-system/internal/coordinator" "chat-agent-system/internal/docgov" "chat-agent-system/internal/taskrun" ) // ActionServices 对话层执行 PendingAction 所需的后端服务。 type ActionServices struct { DocGov *docgov.GovernanceEngine Bizdev bizdev.BizdevService TaskRuns *taskrun.Manager } // ActionExecResult 动作执行结果摘要。 type ActionExecResult struct { DocState string RunID string Message string } func parseUserID(userID string) int64 { id, _ := strconv.ParseInt(strings.TrimSpace(userID), 10, 64) return id } func actorName(userCtx *coordinator.UserProjectContext) string { if userCtx == nil { return "用户" } if userCtx.User.Name != "" { return userCtx.User.Name } return "用户" } func (s *Session) executeAction(ctx context.Context, action *coordinator.PendingAction, userCtx *coordinator.UserProjectContext) (*ActionExecResult, error) { if action == nil || s.Actions == nil { return nil, fmt.Errorf("action services not configured") } uid := s.UserID if uid <= 0 { uid = parseUserID(userCtx.User.ID) } name := actorName(userCtx) switch action.Kind { case "docgov.review_approve": if s.Actions.DocGov == nil { return nil, fmt.Errorf("docgov engine not available") } doc, err := s.Actions.DocGov.ReviewApprove(ctx, action.DocID, uid, docgov.RoleReviewer, name, action.Comment) if err != nil { return nil, err } return &ActionExecResult{DocState: string(doc.CurrentState), Message: "审核通过"}, nil case "docgov.approver_approve": if s.Actions.DocGov == nil { return nil, fmt.Errorf("docgov engine not available") } doc, err := s.Actions.DocGov.ApproverApprove(ctx, action.DocID, uid, docgov.RoleApprover, name, action.Comment) if err != nil { return nil, err } return &ActionExecResult{DocState: string(doc.CurrentState), Message: "终审批准"}, nil case "docgov.reject": if s.Actions.DocGov == nil { return nil, fmt.Errorf("docgov engine not available") } reason := action.Reason if reason == "" { reason = "用户确认驳回" } doc, err := s.Actions.DocGov.ReviewReject(ctx, action.DocID, uid, docgov.RoleReviewer, name, reason) if err != nil { rollback := action.Rollback if rollback == "" { rollback = docgov.StateDrafting } doc, err = s.Actions.DocGov.ApproverReject(ctx, action.DocID, uid, docgov.RoleApprover, name, reason, rollback) if err != nil { return nil, err } } return &ActionExecResult{DocState: string(doc.CurrentState), Message: "驳回完成"}, nil case "taskrun.resume", "taskrun.restart": if s.Actions.TaskRuns == nil || s.Actions.Bizdev == nil { return nil, fmt.Errorf("task run services not available") } taskKey := action.TaskKey if taskKey == "" { taskKey = "intake" } runID := fmt.Sprintf("run_%d", time.Now().UnixNano()) resumeDir := "" if action.Kind == "taskrun.resume" { resumeDir = action.WorkDir } taskReq := bizdev.TaskRunRequest{ TaskKey: taskKey, ProjectName: userCtx.Project.Name, UserID: uid, ProjectID: s.ProjectID, SessionID: s.ID, } record := &taskrun.RunRecord{ RunID: runID, SessionID: s.ID, ProjectID: s.ProjectID, UserID: uid, TaskKey: taskKey, Status: "running", } created, err := s.Actions.TaskRuns.CreateAndStart(ctx, runID, record, taskReq, bizdev.StageRunRequest{}, resumeDir) if err != nil { return nil, err } return &ActionExecResult{RunID: created.RunID, Message: "任务已启动"}, nil default: return nil, fmt.Errorf("unsupported pending action: %s", action.Kind) } } func renderActionReply(action *coordinator.PendingAction, result *ActionExecResult, execErr error) string { docName := action.DocID if docName == "" { docName = "当前任务" } if execErr != nil { return fmt.Sprintf("操作未能完成:%s", execErr.Error()) } if result == nil { return "操作已完成。" } switch action.Kind { case "docgov.review_approve": return fmt.Sprintf("已确认审核通过!《%s》已流转至批准环节(当前状态:%s)。", docName, result.DocState) case "docgov.approver_approve": return fmt.Sprintf("已确认终审批准!《%s》已被法定受控锁定并正式归档生效(当前状态:%s)。", docName, result.DocState) case "docgov.reject": return fmt.Sprintf("已确认执行驳回操作!《%s》已退回(当前状态:%s),驳回意见已同步下发。", docName, result.DocState) case "taskrun.resume": return fmt.Sprintf("续跑任务已启动(run_id=%s)。您可在任务面板查看进度。", result.RunID) case "taskrun.restart": return fmt.Sprintf("任务已重新启动(run_id=%s)。您可在任务面板查看进度。", result.RunID) default: if result.Message != "" { return result.Message } return "操作已完成。" } }