fix(providers): surface clear arrearage warning on quota/billing errors (#3006)

This commit is contained in:
04cb
2026-05-29 15:31:17 +08:00
committed by Xubin Ren
parent 672fabe5be
commit 9d3fe7c34b
4 changed files with 70 additions and 1 deletions
+25
View File
@@ -78,6 +78,31 @@ async def test_llm_error_not_appended_to_session_messages():
assert assistant_msgs[-1]["content"] == _PERSISTED_MODEL_ERROR_PLACEHOLDER
@pytest.mark.asyncio
async def test_llm_arrearage_error_surfaces_clear_message():
"""Arrearage errors yield a clear user-facing message, not a raw dump (#3006)."""
from nanobot.agent.runner import AgentRunSpec, AgentRunner, _ARREARAGE_ERROR_MESSAGE
provider = MagicMock(spec=LLMProvider)
provider.chat_with_retry = AsyncMock(return_value=LLMResponse(
content="HTTP 402 insufficient_quota", finish_reason="error", error_status_code=402,
))
tools = MagicMock()
tools.get_definitions.return_value = []
runner = AgentRunner(provider)
result = await runner.run(AgentRunSpec(
initial_messages=[{"role": "user", "content": "hello"}],
tools=tools,
model="test-model",
max_iterations=5,
max_tool_result_chars=_MAX_TOOL_RESULT_CHARS,
))
assert result.stop_reason == "error"
assert result.final_content == _ARREARAGE_ERROR_MESSAGE
@pytest.mark.asyncio
async def test_runner_tool_error_sets_final_content():
from nanobot.agent.runner import AgentRunSpec, AgentRunner
@@ -1,6 +1,9 @@
from types import SimpleNamespace
import pytest
from nanobot.providers.anthropic_provider import AnthropicProvider
from nanobot.providers.base import LLMProvider, LLMResponse
from nanobot.providers.openai_compat_provider import OpenAICompatProvider
@@ -79,3 +82,14 @@ def test_anthropic_handle_error_marks_connection_kind() -> None:
assert response.finish_reason == "error"
assert response.error_kind == "connection"
@pytest.mark.parametrize("expected, kwargs", [
(True, {"error_status_code": 402}), # HTTP 402
(True, {"error_type": "insufficient_quota"}), # billing token
(True, {"content": "429 You exceeded your current quota"}), # text marker
(False, {"error_status_code": 429, "error_type": "rate_limit_exceeded"}), # plain rate limit
])
def test_is_arrearage_response(expected: bool, kwargs: dict) -> None:
response = LLMResponse(finish_reason="error", **{"content": "boom", **kwargs})
assert LLMProvider.is_arrearage_response(response) is expected