fix(retry): recognize ZhiPu 1302 rate-limit error for retry
ZhiPu API returns code 1302 with Chinese text "速率限制" instead of standard HTTP 429 + "rate limit", causing the retry engine to treat it as non-transient and fail immediately.
This commit is contained in:
@@ -108,6 +108,7 @@ class LLMProvider(ABC):
|
||||
"connection",
|
||||
"server error",
|
||||
"temporarily unavailable",
|
||||
"速率限制",
|
||||
)
|
||||
_RETRYABLE_STATUS_CODES = frozenset({408, 409, 429})
|
||||
_TRANSIENT_ERROR_KINDS = frozenset({"timeout", "connection"})
|
||||
@@ -154,6 +155,7 @@ class LLMProvider(ABC):
|
||||
"temporarily unavailable",
|
||||
"overloaded",
|
||||
"concurrency limit",
|
||||
"速率限制",
|
||||
)
|
||||
|
||||
_SENTINEL = object()
|
||||
|
||||
@@ -546,6 +546,56 @@ async def test_chat_with_retry_normalizes_explicit_none_max_tokens() -> None:
|
||||
assert provider.last_kwargs["temperature"] == 0.7
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_chat_with_retry_retries_zhipu_1302_rate_limit(monkeypatch) -> None:
|
||||
"""ZhiPu returns code 1302 with Chinese rate-limit text instead of HTTP 429."""
|
||||
provider = ScriptedProvider([
|
||||
LLMResponse(
|
||||
content='Error: {\'code\': \'1302\', \'message\': \'您的账户已达到速率限制,请您控制请求频率\'}',
|
||||
finish_reason="error",
|
||||
),
|
||||
LLMResponse(content="ok"),
|
||||
])
|
||||
delays: list[float] = []
|
||||
|
||||
async def _fake_sleep(delay: float) -> None:
|
||||
delays.append(delay)
|
||||
|
||||
monkeypatch.setattr("nanobot.providers.base.asyncio.sleep", _fake_sleep)
|
||||
|
||||
response = await provider.chat_with_retry(messages=[{"role": "user", "content": "hello"}])
|
||||
|
||||
assert response.content == "ok"
|
||||
assert provider.calls == 2
|
||||
assert delays == [1]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_chat_with_retry_retries_zhipu_1302_with_429_status(monkeypatch) -> None:
|
||||
"""ZhiPu 1302 error with HTTP 429 status should also retry."""
|
||||
provider = ScriptedProvider([
|
||||
LLMResponse(
|
||||
content='Error: {\'code\': \'1302\', \'message\': \'您的账户已达到速率限制,请您控制请求频率\'}',
|
||||
finish_reason="error",
|
||||
error_status_code=429,
|
||||
error_code="1302",
|
||||
),
|
||||
LLMResponse(content="ok"),
|
||||
])
|
||||
delays: list[float] = []
|
||||
|
||||
async def _fake_sleep(delay: float) -> None:
|
||||
delays.append(delay)
|
||||
|
||||
monkeypatch.setattr("nanobot.providers.base.asyncio.sleep", _fake_sleep)
|
||||
|
||||
response = await provider.chat_with_retry(messages=[{"role": "user", "content": "hello"}])
|
||||
|
||||
assert response.content == "ok"
|
||||
assert provider.calls == 2
|
||||
assert delays == [1]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_chat_stream_with_retry_normalizes_explicit_none_max_tokens() -> None:
|
||||
"""chat_stream_with_retry must apply the same None-guard as chat_with_retry."""
|
||||
|
||||
Reference in New Issue
Block a user