package httpapi import ( "net/http" "strings" "github.com/easyai/easyai-ai-gateway/apps/api/internal/publicerror" "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) func publicGatewayTask(task store.GatewayTask) store.GatewayTask { if task.Status == "failed" || task.Status == "cancelled" || task.ErrorCode != "" || task.ErrorMessage != "" { value := publicerror.FromFields(task.ErrorCode, firstNonEmpty(task.ErrorMessage, task.Error), storedTaskErrorStatus(task.ErrorCode), false) if task.PublicError != nil && task.PublicError.Code != "" { value = *task.PublicError } value = publicerror.WithIDs(value, task.RequestID, task.ID) publicerror.Observe(value) task.PublicError = &value task.ErrorCode = value.Code task.ErrorMessage = value.Message task.Error = value.Message } for index := range task.Attempts { attempt := &task.Attempts[index] if attempt.ErrorCode == "" && attempt.ErrorMessage == "" { continue } status := attempt.StatusCode if status <= 0 { status = http.StatusBadGateway } value := publicerror.FromFields(attempt.ErrorCode, attempt.ErrorMessage, status, attempt.Retryable) if attempt.PublicError != nil && attempt.PublicError.Code != "" { value = *attempt.PublicError } value = publicerror.WithIDs(value, attempt.RequestID, task.ID) attempt.PublicError = &value attempt.ErrorCode = value.Code attempt.ErrorMessage = value.Message } return task } func publicTaskError(task store.GatewayTask) publicerror.Error { if task.PublicError != nil && task.PublicError.Code != "" { return publicerror.WithIDs(*task.PublicError, task.RequestID, task.ID) } status := storedTaskErrorStatus(task.ErrorCode) if status <= 0 { status = http.StatusBadGateway } return publicerror.WithIDs(publicerror.FromFields(task.ErrorCode, firstNonEmpty(task.ErrorMessage, task.Error, task.Message), status, false), task.RequestID, task.ID) } func publicTaskList(items []store.GatewayTask) []store.GatewayTask { out := make([]store.GatewayTask, len(items)) for index, task := range items { out[index] = publicGatewayTask(task) } return out } func publicErrorMap(value publicerror.Error) map[string]any { out := map[string]any{ "code": value.Code, "message": value.Message, "category": value.Category, "httpStatus": value.HTTPStatus, "retryable": value.Retryable, "action": value.Action, "version": value.Version, } if value.RetryAfterSeconds > 0 { out["retryAfterSeconds"] = value.RetryAfterSeconds } if requestID := strings.TrimSpace(value.RequestID); requestID != "" { out["requestId"] = requestID } if taskID := strings.TrimSpace(value.TaskID); taskID != "" { out["taskId"] = taskID } return out } func publicErrorWithRetryAfter(value publicerror.Error, details map[string]any) publicerror.Error { if value.RetryAfterSeconds > 0 || details == nil { return value } switch typed := details["retryAfterSeconds"].(type) { case int: value.RetryAfterSeconds = typed case int32: value.RetryAfterSeconds = int(typed) case int64: value.RetryAfterSeconds = int(typed) case float64: value.RetryAfterSeconds = int(typed) } if value.RetryAfterSeconds < 0 { value.RetryAfterSeconds = 0 } return value } func safePublicErrorDetails(details map[string]any, value publicerror.Error, includePublicError bool) map[string]any { out := map[string]any{} for _, key := range []string{"param", "retryAfterSeconds", "recoveryAt", "rateLimit", "pricing"} { if item, ok := details[key]; ok && item != nil { out[key] = item } } if value.Category == "request" { for _, key := range []string{"reason", "diagnosticId"} { if item, ok := details[key]; ok && item != nil { out[key] = item } } } if includePublicError { out["publicError"] = value } return out }