mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(openai_compat): clarify HTML response errors
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user