refreshClientOnAuthError checks if the error is a 401/auth error from an OAuth provider. If so, it invalidates the auth cache, refreshes credentials, and recreates the client. Returns true if the client was refreshed and the caller should retry. A 403 that carries WAF / proxy / firewall signals is
(err error)
| 549 | // the corporate proxy rejected the payload or URL). Such 403s fall |
| 550 | // through for payload-recovery handling further up the call chain. |
| 551 | func (cli *ChatCLI) refreshClientOnAuthError(err error) bool { |
| 552 | if err == nil { |
| 553 | return false |
| 554 | } |
| 555 | if agent.IsProxyWAFRejection(err) { |
| 556 | return false |
| 557 | } |
| 558 | var apiErr *utils.APIError |
| 559 | if errors.As(err, &apiErr) && (apiErr.StatusCode == 401 || apiErr.StatusCode == 403) { |
| 560 | cli.logger.Info("Auth error detected, refreshing OAuth credentials", |
| 561 | zap.Int("status", apiErr.StatusCode), |
| 562 | zap.String("provider", cli.Provider)) |
| 563 | auth.InvalidateCache() |
| 564 | cli.manager.RefreshProviders() |
| 565 | if newClient, cerr := cli.manager.GetClient(cli.Provider, cli.Model); cerr == nil { |
| 566 | cli.mu.Lock() |
| 567 | cli.Client = newClient |
| 568 | cli.mu.Unlock() |
| 569 | return true |
| 570 | } |
| 571 | cli.logger.Warn("Failed to recreate client after auth refresh", |
| 572 | zap.String("provider", cli.Provider)) |
| 573 | } |
| 574 | return false |
| 575 | } |
| 576 | |
| 577 | // getClient returns the current LLM client, safe for use from background goroutines. |
| 578 | func (cli *ChatCLI) getClient() client.LLMClient { |
no test coverage detected