From b321c63e1a35988cad02239b7ec74acc083b5cb5 Mon Sep 17 00:00:00 2001 From: KDB <937925477@qq.com> Date: Sun, 16 Aug 2026 13:59:32 +0800 Subject: [PATCH] test(fallback): classify authentication exception messages --- nanobot/providers/fallback_provider.py | 5 +++-- tests/agent/test_runner_fallback.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/nanobot/providers/fallback_provider.py b/nanobot/providers/fallback_provider.py index e348f28f9..d8a6173d7 100644 --- a/nanobot/providers/fallback_provider.py +++ b/nanobot/providers/fallback_provider.py @@ -623,6 +623,8 @@ class FallbackProvider(LLMProvider): raise except Exception as exc: error_name = type(exc).__name__.lower() + detail = str(exc).strip() or type(exc).__name__ + detail_lower = detail.lower() error_kind: str | None = None error_should_retry: bool | None = None if isinstance(exc, (httpx.TimeoutException, asyncio.TimeoutError)): @@ -634,7 +636,7 @@ class FallbackProvider(LLMProvider): elif any( token in error_name for token in ("auth", "credential", "permissiondenied", "unauthor") - ): + ) or any(token in detail_lower for token in _AUTHENTICATION_ERROR_TOKENS): error_kind = "authentication" elif "ratelimit" in error_name or "throttl" in error_name: error_kind = "rate_limit" @@ -652,7 +654,6 @@ class FallbackProvider(LLMProvider): except (TypeError, ValueError): error_status_code = None - detail = str(exc).strip() or type(exc).__name__ return LLMResponse( content=f"Error calling LLM: {detail}", finish_reason="error", diff --git a/tests/agent/test_runner_fallback.py b/tests/agent/test_runner_fallback.py index 4f850c852..c8297bee3 100644 --- a/tests/agent/test_runner_fallback.py +++ b/tests/agent/test_runner_fallback.py @@ -423,6 +423,19 @@ class TestFallbackWhenPrimaryRaises: assert result.finish_reason == "stop" factory.assert_called_once_with(_fallback("fallback-a")) + @pytest.mark.asyncio + async def test_authentication_exception_message_is_classified(self) -> None: + primary = _RaisingProvider("primary") + + response, exception = await FallbackProvider._call_provider( + lambda provider, kwargs: provider.chat(**kwargs), + primary, + {}, + ) + + assert exception is primary._exc + assert response.error_kind == "authentication" + @pytest.mark.parametrize( "exc", [