若干更新迭代
This commit is contained in:
1 parent
deb9cc5bcf
commit
4ac786aafb
64 files changed
+3251
-291
No files matched your search
@@ -0,0 +1,150 @@
|
||||
package providers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var providerRequestIDInMessage = regexp.MustCompile(`(?i)\brequest[ _-]?id\s*[:=]\s*([A-Za-z0-9_.:-]{3,128})\b`)
|
||||
|
||||
// SanitizeFailureDetail retains a short provider explanation while removing
|
||||
// submitted text, media links, credentials, and unrecognized quoted values.
|
||||
// It is safe to call again after the original request has been discarded.
|
||||
func SanitizeFailureDetail(message string, requestBody []byte, secrets ...string) string {
|
||||
if strings.TrimSpace(message) == "" {
|
||||
return ""
|
||||
}
|
||||
privateValues := append([]string(nil), secrets...)
|
||||
var request any
|
||||
if json.Unmarshal(requestBody, &request) == nil {
|
||||
collectPrivateRequestValues(request, "", &privateValues)
|
||||
}
|
||||
for _, value := range privateValues {
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
message = strings.ReplaceAll(message, value, "[redacted]")
|
||||
encoded, _ := json.Marshal(value)
|
||||
if len(encoded) > 2 {
|
||||
message = strings.ReplaceAll(message, string(encoded[1:len(encoded)-1]), "[redacted]")
|
||||
}
|
||||
}
|
||||
message = minimaxDiagnosticURL.ReplaceAllString(message, "[redacted]")
|
||||
message = minimaxDiagnosticCredential.ReplaceAllString(message, "[redacted]")
|
||||
message = minimaxDiagnosticQuoted.ReplaceAllStringFunc(message, func(quoted string) string {
|
||||
value := quoted[1 : len(quoted)-1]
|
||||
if minimaxDiagnosticValue(value) != "unrecognized" {
|
||||
return quoted
|
||||
}
|
||||
return "[redacted]"
|
||||
})
|
||||
message = minimaxDiagnosticLongToken.ReplaceAllString(message, "[redacted]")
|
||||
message = strings.Join(strings.Fields(message), " ")
|
||||
runes := []rune(message)
|
||||
if len(runes) > 512 {
|
||||
return string(runes[:512]) + "...[truncated]"
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
func collectPrivateRequestValues(value any, key string, values *[]string) {
|
||||
switch typed := value.(type) {
|
||||
case map[string]any:
|
||||
for childKey, childValue := range typed {
|
||||
collectPrivateRequestValues(childValue, strings.ToLower(childKey), values)
|
||||
}
|
||||
case []any:
|
||||
for _, child := range typed {
|
||||
collectPrivateRequestValues(child, key, values)
|
||||
}
|
||||
case string:
|
||||
if strings.Contains(key, "prompt") || strings.Contains(key, "text") || strings.Contains(key, "url") || strings.Contains(key, "image") || strings.Contains(key, "video") || strings.Contains(key, "audio") || strings.Contains(key, "token") || strings.Contains(key, "secret") || strings.Contains(key, "key") || strings.Contains(key, "signature") || strings.Contains(key, "password") || strings.Contains(key, "credential") {
|
||||
*values = append(*values, typed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func requestIDFromMessage(message string) string {
|
||||
match := providerRequestIDInMessage.FindStringSubmatch(message)
|
||||
if len(match) < 2 {
|
||||
return ""
|
||||
}
|
||||
return safeHTTPProviderDiagnosticToken(match[1], 128)
|
||||
}
|
||||
|
||||
func safeProviderResponseDetail(raw, requestBody []byte, secrets ...string) string {
|
||||
root := record(raw)
|
||||
providerError := object(first(root["error"], root["Error"]))
|
||||
output := object(root["output"])
|
||||
data := object(root["data"])
|
||||
task := object(first(root["task"], data["task"]))
|
||||
nestedError := object(first(data["error"], task["error"], output["error"]))
|
||||
metadataError := object(first(object(first(root["ResponseMetadata"], root["response_metadata"]))["Error"], object(first(root["ResponseMetadata"], root["response_metadata"]))["error"]))
|
||||
message := stringValue(providerError["message"], providerError["Message"], nestedError["message"], nestedError["Message"], task["message"], output["message"], data["message"], metadataError["Message"], metadataError["message"], root["message"], root["Message"])
|
||||
return SanitizeFailureDetail(message, requestBody, secrets...)
|
||||
}
|
||||
|
||||
func successBusinessCode(code string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(code)) {
|
||||
case "", "0", "200", "ok", "success", "10000":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Only explicit top-level or output error indicators count as a business
|
||||
// rejection. A successful task can carry a normal informational message.
|
||||
func inspectProviderBusinessRejection(raw []byte, headers http.Header, requestBody []byte, secrets ...string) (code, requestID, detail string, rejected bool) {
|
||||
root := record(raw)
|
||||
providerError := object(first(root["error"], root["Error"]))
|
||||
output := object(root["output"])
|
||||
data := object(root["data"])
|
||||
task := object(first(root["task"], data["task"]))
|
||||
nestedError := object(first(data["error"], task["error"], output["error"]))
|
||||
code, requestID, _ = inspectHTTPProviderFailure(raw, headers)
|
||||
message := stringValue(providerError["message"], providerError["Message"], nestedError["message"], nestedError["Message"], output["message"], data["message"], root["message"])
|
||||
if (len(providerError) > 0 || len(nestedError) > 0) && (code != "" || message != "") {
|
||||
rejected = true
|
||||
} else if rootCode := safeHTTPProviderDiagnosticToken(first(root["code"], root["Code"]), 64); rootCode != "" && !successBusinessCode(rootCode) {
|
||||
rejected = true
|
||||
} else if outputCode := safeHTTPProviderDiagnosticToken(first(output["code"], output["Code"]), 64); outputCode != "" && !successBusinessCode(outputCode) {
|
||||
rejected = true
|
||||
} else if strings.EqualFold(stringValue(root["type"]), "error") && message != "" {
|
||||
rejected = true
|
||||
}
|
||||
if !rejected {
|
||||
return "", "", "", false
|
||||
}
|
||||
return code, requestID, SanitizeFailureDetail(message, requestBody, secrets...), true
|
||||
}
|
||||
|
||||
func annotateTerminalFailure(result Result, raw []byte, headers http.Header, requestBody []byte, secrets ...string) Result {
|
||||
if result.Status != StatusFailed && result.Status != StatusExpired && result.Status != StatusCancelled {
|
||||
return result
|
||||
}
|
||||
root := record(raw)
|
||||
business := object(first(root["Result"], root["result"]))
|
||||
data := object(root["data"])
|
||||
businessData := object(first(business["data"], business["Data"]))
|
||||
output := object(root["output"])
|
||||
task := object(root["task"])
|
||||
providerError := object(first(task["error"], data["error"], businessData["error"], businessData["Error"], business["error"], business["Error"], output["error"], root["error"], root["Error"]))
|
||||
code, requestID, _ := inspectHTTPProviderFailure(raw, headers)
|
||||
if nestedCode := firstSafeHTTPProviderDiagnosticToken(64, providerError["code"], providerError["Code"], task["error_code"], data["error_code"], businessData["error_code"], business["error_code"]); nestedCode != "" {
|
||||
code = nestedCode
|
||||
}
|
||||
if nestedID := firstSafeHTTPProviderDiagnosticToken(128, providerError["request_id"], providerError["requestId"], providerError["RequestId"], task["request_id"], data["request_id"], businessData["request_id"], business["request_id"]); nestedID != "" {
|
||||
requestID = nestedID
|
||||
}
|
||||
message := stringValue(providerError["message"], providerError["Message"], task["error_message"], task["message"], output["message"], data["error_message"], data["message"], businessData["error_message"], businessData["message"], business["message"], root["message"], result.ErrorMessage)
|
||||
if requestID == "" {
|
||||
requestID = requestIDFromMessage(message)
|
||||
}
|
||||
result.ErrorCode = code
|
||||
result.RequestID = requestID
|
||||
result.ErrorDetail = SanitizeFailureDetail(message, requestBody, secrets...)
|
||||
result.ErrorMessage = SanitizeFailureDetail(result.ErrorMessage, requestBody, secrets...)
|
||||
return result
|
||||
}
|
||||
Reference in new issue
Block a user