Files
Agent-System/internal/server/workflow_instance_handlers.go
T
weichenandCursor f6813cc272 feat(api): add additive HTTP/SSE error envelopes
Public errors now emit code, safe message, and request_id while keeping the legacy error field. Raw SQL, paths, tokens, and XSS payloads are stripped; the frontend branches on code instead of substring matching.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 14:40:56 +00:00

105 lines
3.4 KiB
Go

package server
import (
"encoding/json"
"net/http"
"strconv"
"chat-agent-system/internal/projectinstance"
)
func (s *Server) handleGetWorkflowInstance(w http.ResponseWriter, r *http.Request) {
instanceID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil || instanceID <= 0 {
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM","message":"invalid instance id"}`)
return
}
if s.instSvc == nil || !s.instSvc.Available() {
writeSafeError(w, r, http.StatusServiceUnavailable, `{"error":"ERR_NOT_AVAILABLE","message":"项目实例服务不可用"}`)
return
}
detail, err := s.instSvc.GetInstanceDetail(r.Context(), instanceID)
if err != nil {
writeProjectInstanceError(w, err)
return
}
if _, ok := s.requireProjectAccess(w, r, detail.Instance.ProjectID); !ok {
return
}
writeJSONResponse(w, http.StatusOK, detail)
}
func (s *Server) handleGetStageReadiness(w http.ResponseWriter, r *http.Request) {
instanceID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil || instanceID <= 0 {
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM","message":"invalid instance id"}`)
return
}
stageKey := r.PathValue("stage")
if s.instSvc == nil || !s.instSvc.Available() {
writeSafeError(w, r, http.StatusServiceUnavailable, `{"error":"ERR_NOT_AVAILABLE","message":"项目实例服务不可用"}`)
return
}
detail, err := s.instSvc.GetInstanceDetail(r.Context(), instanceID)
if err != nil {
writeProjectInstanceError(w, err)
return
}
user, ok := s.requireProjectAccess(w, r, detail.Instance.ProjectID)
if !ok {
return
}
isCreator, _ := s.pwSvc.IsProjectCreator(r.Context(), detail.Instance.ProjectID, user.ID)
readiness, err := s.instSvc.GetStageReadiness(r.Context(), instanceID, stageKey, user.ID, isCreator)
if err != nil {
writeProjectInstanceError(w, err)
return
}
writeJSONResponse(w, http.StatusOK, readiness)
}
func (s *Server) handleAdvanceStage(w http.ResponseWriter, r *http.Request) {
instanceID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil || instanceID <= 0 {
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM","message":"invalid instance id"}`)
return
}
stageKey := r.PathValue("stage")
if s.instSvc == nil || !s.instSvc.Available() {
writeSafeError(w, r, http.StatusServiceUnavailable, `{"error":"ERR_NOT_AVAILABLE","message":"项目实例服务不可用"}`)
return
}
detail, err := s.instSvc.GetInstanceDetail(r.Context(), instanceID)
if err != nil {
writeProjectInstanceError(w, err)
return
}
user, ok := s.requireProjectAccess(w, r, detail.Instance.ProjectID)
if !ok {
return
}
isCreator, _ := s.pwSvc.IsProjectCreator(r.Context(), detail.Instance.ProjectID, user.ID)
var req projectinstance.AdvanceStageInput
if err := json.NewDecoder(r.Body).Decode(&req); err != nil && r.ContentLength > 0 {
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM","message":"无效的 JSON 请求体"}`)
return
}
if req.StageKey == "" {
req.StageKey = stageKey
}
result, err := s.instSvc.AdvanceStage(r.Context(), instanceID, user.ID, isCreator, req)
if err != nil {
writeProjectInstanceError(w, err)
return
}
if s.notifySvc != nil && result.CompletedStageInstanceID > 0 {
_ = s.notifySvc.ConfirmStageAdvanceRequest(
r.Context(),
result.CompletedStageInstanceID,
result.CompletedReadinessRevision,
user.ID,
)
}
writeJSONResponse(w, http.StatusOK, result)
}