From 0112ba676b68d6daf3add4c7c8705e66815174ae Mon Sep 17 00:00:00 2001 From: XYSK-lilong007 <267018309+XYSK-lilong007@users.noreply.github.com> Date: Fri, 13 Mar 2026 08:13:50 +0800 Subject: [PATCH] fix(provider): classify transport send failures for fallback --- pkg/providers/error_classifier.go | 6 ++++++ pkg/providers/error_classifier_test.go | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/pkg/providers/error_classifier.go b/pkg/providers/error_classifier.go index fd9bf1e81..a0c0881af 100644 --- a/pkg/providers/error_classifier.go +++ b/pkg/providers/error_classifier.go @@ -48,6 +48,12 @@ var ( substr("timed out"), substr("deadline exceeded"), substr("context deadline exceeded"), + substr("failed to send request"), + substr("connection reset by peer"), + substr("connection refused"), + substr("no route to host"), + substr("unexpected eof"), + substr("tls handshake timeout"), } billingPatterns = []errorPattern{ diff --git a/pkg/providers/error_classifier_test.go b/pkg/providers/error_classifier_test.go index 67d9af62b..098e5ec08 100644 --- a/pkg/providers/error_classifier_test.go +++ b/pkg/providers/error_classifier_test.go @@ -154,6 +154,28 @@ func TestClassifyError_TimeoutPatterns(t *testing.T) { } } +func TestClassifyError_TransportSendPatterns(t *testing.T) { + patterns := []string{ + `failed to send request: Post "https://openrouter.ai/api/v1/chat/completions": read tcp 127.0.0.1:1->127.0.0.1:2: read: connection reset by peer`, + `failed to send request: dial tcp 127.0.0.1:443: connect: connection refused`, + `failed to send request: dial tcp 127.0.0.1:443: connect: no route to host`, + `failed to send request: Post "https://openrouter.ai/api/v1/chat/completions": unexpected EOF`, + `failed to send request: tls handshake timeout`, + } + + for _, msg := range patterns { + err := errors.New(msg) + result := ClassifyError(err, "openrouter", "stepfun/step-3.5-flash") + if result == nil { + t.Errorf("pattern %q: expected non-nil", msg) + continue + } + if result.Reason != FailoverTimeout { + t.Errorf("pattern %q: reason = %q, want timeout", msg, result.Reason) + } + } +} + func TestClassifyError_AuthPatterns(t *testing.T) { patterns := []string{ "invalid api key",