mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-12 06:13:57 +00:00
74 lines
2.6 KiB
Go
74 lines
2.6 KiB
Go
package channels
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/providers"
|
|
)
|
|
|
|
// isTransientFailureMessage reports whether an agent run failure string is a
|
|
// transient provider error (rate limit, timeout, overload, connection drop)
|
|
// that the user can simply retry — as opposed to a permanent error (auth,
|
|
// context overflow). Used to decide whether a failure should surface a
|
|
// terminal 💔 reaction (see events.go reaction forwarding).
|
|
func isTransientFailureMessage(errStr string) bool {
|
|
if errStr == "" {
|
|
return false
|
|
}
|
|
lower := strings.ToLower(errStr)
|
|
// Reuse the provider retryability classifier (429/5xx typed errors,
|
|
// connection reset, timeouts, rate limits, EOF) on the raw message.
|
|
if providers.IsRetryableError(errors.New(errStr)) {
|
|
return true
|
|
}
|
|
// Mirror FormatAgentError's transient matchers (rate limit, timeout,
|
|
// overload) plus HTTP 5xx status codes, which IsRetryableError only matches
|
|
// on typed HTTPError values — the string seen here has been re-wrapped.
|
|
return strings.Contains(lower, "rate limit") ||
|
|
strings.Contains(lower, "too many requests") ||
|
|
strings.Contains(lower, "429") ||
|
|
strings.Contains(lower, "timeout") ||
|
|
strings.Contains(lower, "deadline exceeded") ||
|
|
strings.Contains(lower, "overload") ||
|
|
strings.Contains(lower, "http 5")
|
|
}
|
|
|
|
// FormatAgentError converts internal error to user-friendly message.
|
|
// Issue 958: Send user-friendly error on RunFailed instead of silent "...".
|
|
func FormatAgentError(errStr string) string {
|
|
if errStr == "" {
|
|
return ""
|
|
}
|
|
|
|
lower := strings.ToLower(errStr)
|
|
|
|
// Context overflow (highest priority — specific actionable message)
|
|
if providers.IsContextOverflowMessage(lower) {
|
|
return "⚠️ The conversation has grown too long. Please start a new chat or ask me to summarize."
|
|
}
|
|
|
|
// Rate limit
|
|
if strings.Contains(lower, "rate limit") || strings.Contains(lower, "too many requests") || strings.Contains(lower, "429") {
|
|
return "⏳ Too many requests. Please wait a moment and try again."
|
|
}
|
|
|
|
// Auth errors
|
|
if strings.Contains(lower, "unauthorized") || strings.Contains(lower, "invalid api key") || strings.Contains(lower, "401") || strings.Contains(lower, "403") {
|
|
return "🔑 Authentication error. Please check your API configuration."
|
|
}
|
|
|
|
// Timeout
|
|
if strings.Contains(lower, "timeout") || strings.Contains(lower, "deadline exceeded") {
|
|
return "⏱️ Request timed out. Please try again."
|
|
}
|
|
|
|
// Overloaded
|
|
if strings.Contains(lower, "overload") {
|
|
return "🔄 Service is busy. Please try again in a moment."
|
|
}
|
|
|
|
// Generic fallback (don't expose internal error details)
|
|
return "❌ Something went wrong. Please try again."
|
|
}
|