fix(openai_compat): clarify HTML response errors

This commit is contained in:
qs3c
2026-03-04 17:50:46 +08:00
parent b82bb9acc0
commit 4946a8b449
2 changed files with 68 additions and 1 deletions
+47 -1
View File
@@ -192,7 +192,53 @@ func (p *Provider) Chat(
return nil, fmt.Errorf("API request failed:\n Status: %d\n Body: %s", resp.StatusCode, string(body))
}
return parseResponse(body)
out, err := parseResponse(body)
if err != nil {
return nil, wrapResponseParseError(err, body, resp.Header.Get("Content-Type"), p.apiBase)
}
return out, nil
}
func wrapResponseParseError(err error, body []byte, contentType, apiBase string) error {
trimmedContentType := strings.TrimSpace(contentType)
if looksLikeHTML(body, trimmedContentType) {
contentTypeHint := ""
if trimmedContentType != "" {
contentTypeHint = fmt.Sprintf(" (content-type: %s)", trimmedContentType)
}
return fmt.Errorf(
"expected JSON response from %s/chat/completions, but received HTML%s; check api_base or proxy configuration. Response preview: %s",
apiBase,
contentTypeHint,
responsePreview(body, 160),
)
}
return err
}
func looksLikeHTML(body []byte, contentType string) bool {
contentType = strings.ToLower(strings.TrimSpace(contentType))
if strings.Contains(contentType, "text/html") || strings.Contains(contentType, "application/xhtml+xml") {
return true
}
trimmed := strings.ToLower(strings.TrimSpace(string(body)))
return strings.HasPrefix(trimmed, "<!doctype html") ||
strings.HasPrefix(trimmed, "<html") ||
strings.HasPrefix(trimmed, "<head") ||
strings.HasPrefix(trimmed, "<body")
}
func responsePreview(body []byte, max int) string {
preview := strings.TrimSpace(string(body))
if preview == "" {
return "<empty>"
}
if len(preview) <= max {
return preview
}
return preview[:max] + "..."
}
func parseResponse(body []byte) (*LLMResponse, error) {
@@ -212,6 +212,27 @@ func TestProviderChat_HTTPError(t *testing.T) {
}
}
func TestProviderChat_HTMLSuccessResponseReturnsHelpfulError(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("<!DOCTYPE html><html><body>gateway login</body></html>"))
}))
defer server.Close()
p := NewProvider("key", server.URL, "")
_, err := p.Chat(t.Context(), []Message{{Role: "user", Content: "hi"}}, nil, "gpt-4o", nil)
if err == nil {
t.Fatal("expected error, got nil")
}
if !strings.Contains(err.Error(), "received HTML") {
t.Fatalf("expected helpful HTML error, got %v", err)
}
if !strings.Contains(err.Error(), "check api_base or proxy configuration") {
t.Fatalf("expected configuration hint, got %v", err)
}
}
func TestProviderChat_StripsMoonshotPrefixAndNormalizesKimiTemperature(t *testing.T) {
var requestBody map[string]any