fix(providers): make generic 400 errors retriable and fix double error message
Remove blanket 400 → FailoverFormat mapping from classifyByStatus.
Status 400 is too broad - model-invalid, format, and unknown errors all
return 400. Now 400 errors are classified by message patterns only:
- modelInvalidPatterns → FailoverModelInvalid (retriable + warning)
- formatPatterns → FailoverFormat (non-retriable)
- no match → unknown (retriable, allows fallback)
Also fix double error message: Run() was sending a duplicate error to
the user channel when runAgentLoop had already sent the ⚠️ error.
This commit is contained in:
parent
5f53e40260
commit
c16711ee7e
3 changed files with 10 additions and 4 deletions
|
|
@ -169,7 +169,12 @@ func (al *AgentLoop) Run(ctx context.Context) error {
|
||||||
|
|
||||||
response, err := al.processMessage(ctx, msg)
|
response, err := al.processMessage(ctx, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response = fmt.Sprintf("Error processing message: %v", err)
|
// Error already sent to user channel by runAgentLoop, just log here
|
||||||
|
logger.ErrorCF("agent", "Message processing failed", map[string]any{
|
||||||
|
"error": err.Error(),
|
||||||
|
"channel": msg.Channel,
|
||||||
|
"chat_id": msg.ChatID,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if response != "" {
|
if response != "" {
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,9 @@ func ClassifyError(err error, provider, model string) *FailoverError {
|
||||||
}
|
}
|
||||||
|
|
||||||
// classifyByStatus maps HTTP status codes to FailoverReason.
|
// classifyByStatus maps HTTP status codes to FailoverReason.
|
||||||
|
// NOTE: 400 is intentionally NOT mapped here. Status 400 is too broad
|
||||||
|
// (model-invalid, format errors, unknown API errors all return 400).
|
||||||
|
// Instead, 400 errors are classified by message patterns in classifyByMessage.
|
||||||
func classifyByStatus(status int) FailoverReason {
|
func classifyByStatus(status int) FailoverReason {
|
||||||
switch {
|
switch {
|
||||||
case status == 401 || status == 403:
|
case status == 401 || status == 403:
|
||||||
|
|
@ -192,8 +195,6 @@ func classifyByStatus(status int) FailoverReason {
|
||||||
return FailoverTimeout
|
return FailoverTimeout
|
||||||
case status == 429:
|
case status == 429:
|
||||||
return FailoverRateLimit
|
return FailoverRateLimit
|
||||||
case status == 400:
|
|
||||||
return FailoverFormat
|
|
||||||
case transientStatusCodes[status]:
|
case transientStatusCodes[status]:
|
||||||
return FailoverTimeout
|
return FailoverTimeout
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ func TestClassifyError_StatusCodes(t *testing.T) {
|
||||||
{402, FailoverBilling},
|
{402, FailoverBilling},
|
||||||
{408, FailoverTimeout},
|
{408, FailoverTimeout},
|
||||||
{429, FailoverRateLimit},
|
{429, FailoverRateLimit},
|
||||||
{400, FailoverFormat},
|
// 400 is intentionally NOT here - classified by message patterns, not status code
|
||||||
{500, FailoverTimeout},
|
{500, FailoverTimeout},
|
||||||
{502, FailoverTimeout},
|
{502, FailoverTimeout},
|
||||||
{503, FailoverTimeout},
|
{503, FailoverTimeout},
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue