mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-09-03 17:52:00 +03:00
fix(fallback): normalize exception metadata before retry decisions
Provider exceptions may expose numeric error_type or error_code values. Convert those fields at the response boundary before fallback consumers apply string operations, and cover the behavior with a regression test.
This commit is contained in:
@@ -987,14 +987,16 @@ class LLMProvider(ABC):
|
|||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
error_status_code = None
|
error_status_code = None
|
||||||
|
|
||||||
|
raw_error_type = getattr(exc, "error_type", None)
|
||||||
|
raw_error_code = getattr(exc, "error_code", None)
|
||||||
detail = str(exc).strip() or type(exc).__name__
|
detail = str(exc).strip() or type(exc).__name__
|
||||||
return LLMResponse(
|
return LLMResponse(
|
||||||
content=f"Error calling LLM: {detail}",
|
content=f"Error calling LLM: {detail}",
|
||||||
finish_reason="error",
|
finish_reason="error",
|
||||||
error_status_code=error_status_code,
|
error_status_code=error_status_code,
|
||||||
error_kind=error_kind,
|
error_kind=error_kind,
|
||||||
error_type=getattr(exc, "error_type", None),
|
error_type=str(raw_error_type) if raw_error_type is not None else None,
|
||||||
error_code=getattr(exc, "error_code", None),
|
error_code=str(raw_error_code) if raw_error_code is not None else None,
|
||||||
error_should_retry=error_should_retry,
|
error_should_retry=error_should_retry,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -460,6 +460,28 @@ class TestFallbackWhenPrimaryRaises:
|
|||||||
assert exception is primary._exc
|
assert exception is primary._exc
|
||||||
assert response.error_kind == "authentication"
|
assert response.error_kind == "authentication"
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_non_string_exception_metadata_is_normalized_before_fallback(self) -> None:
|
||||||
|
"""Provider exception metadata must be string-like before fallback consumes it."""
|
||||||
|
|
||||||
|
class NumericMetadataError(Exception):
|
||||||
|
error_type = 429
|
||||||
|
error_code = 429
|
||||||
|
status_code = 429
|
||||||
|
|
||||||
|
primary = _RaisingProvider("primary", NumericMetadataError("rate limited"))
|
||||||
|
|
||||||
|
response, exception = await FallbackProvider._call_provider(
|
||||||
|
lambda provider, kwargs: provider.chat(**kwargs),
|
||||||
|
primary,
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert exception is primary._exc
|
||||||
|
assert response.error_type == "429"
|
||||||
|
assert response.error_code == "429"
|
||||||
|
assert FallbackProvider._should_fallback(response) is True
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"exc",
|
"exc",
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in New Issue
Block a user