Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pkg/providers/error_classifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
22 changes: 22 additions & 0 deletions pkg/providers/error_classifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading