fix(auth): honor disable-cooling and enrich no-auth errors

This commit is contained in:
zilianpn
2026-04-07 00:24:08 +08:00
parent ada8e2905e
commit 0ea768011b
6 changed files with 436 additions and 35 deletions
+53 -1
View File
@@ -6,6 +6,7 @@ package handlers
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
@@ -492,6 +493,7 @@ func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType
opts.Metadata = reqMeta
resp, err := h.AuthManager.Execute(ctx, providers, req, opts)
if err != nil {
err = enrichAuthSelectionError(err, providers, normalizedModel)
status := http.StatusInternalServerError
if se, ok := err.(interface{ StatusCode() int }); ok && se != nil {
if code := se.StatusCode(); code > 0 {
@@ -538,6 +540,7 @@ func (h *BaseAPIHandler) ExecuteCountWithAuthManager(ctx context.Context, handle
opts.Metadata = reqMeta
resp, err := h.AuthManager.ExecuteCount(ctx, providers, req, opts)
if err != nil {
err = enrichAuthSelectionError(err, providers, normalizedModel)
status := http.StatusInternalServerError
if se, ok := err.(interface{ StatusCode() int }); ok && se != nil {
if code := se.StatusCode(); code > 0 {
@@ -588,6 +591,7 @@ func (h *BaseAPIHandler) ExecuteStreamWithAuthManager(ctx context.Context, handl
opts.Metadata = reqMeta
streamResult, err := h.AuthManager.ExecuteStream(ctx, providers, req, opts)
if err != nil {
err = enrichAuthSelectionError(err, providers, normalizedModel)
errChan := make(chan *interfaces.ErrorMessage, 1)
status := http.StatusInternalServerError
if se, ok := err.(interface{ StatusCode() int }); ok && se != nil {
@@ -697,7 +701,7 @@ func (h *BaseAPIHandler) ExecuteStreamWithAuthManager(ctx context.Context, handl
chunks = retryResult.Chunks
continue outer
}
streamErr = retryErr
streamErr = enrichAuthSelectionError(retryErr, providers, normalizedModel)
}
}
@@ -840,6 +844,54 @@ func replaceHeader(dst http.Header, src http.Header) {
}
}
func enrichAuthSelectionError(err error, providers []string, model string) error {
if err == nil {
return nil
}
var authErr *coreauth.Error
if !errors.As(err, &authErr) || authErr == nil {
return err
}
code := strings.TrimSpace(authErr.Code)
if code != "auth_not_found" && code != "auth_unavailable" {
return err
}
providerText := strings.Join(providers, ",")
if providerText == "" {
providerText = "unknown"
}
modelText := strings.TrimSpace(model)
if modelText == "" {
modelText = "unknown"
}
baseMessage := strings.TrimSpace(authErr.Message)
if baseMessage == "" {
baseMessage = "no auth available"
}
detail := fmt.Sprintf("%s (providers=%s, model=%s)", baseMessage, providerText, modelText)
// Clarify the most common alias confusion between Anthropic route names and internal provider keys.
if strings.Contains(","+providerText+",", ",claude,") {
detail += "; check Claude auth/key session and cooldown state via /v0/management/auth-files"
}
status := authErr.HTTPStatus
if status <= 0 {
status = http.StatusServiceUnavailable
}
return &coreauth.Error{
Code: authErr.Code,
Message: detail,
Retryable: authErr.Retryable,
HTTPStatus: status,
}
}
// WriteErrorResponse writes an error message to the response writer using the HTTP status embedded in the message.
func (h *BaseAPIHandler) WriteErrorResponse(c *gin.Context, msg *interfaces.ErrorMessage) {
status := http.StatusInternalServerError