v2.7.1 (#551)
Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai> Co-authored-by: Jean-Malo Delignon <56539593+jean-malo@users.noreply.github.com> Co-authored-by: Paul Cacheux <paul.cacheux@mistral.ai> Co-authored-by: Quentin <torroba.q@gmail.com> Co-authored-by: angelapopopo <angele.lenglemetz@mistral.ai> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
parent
6a50d1d521
commit
54b9a17457
30 changed files with 1000 additions and 200 deletions
74
tests/core/test_backend_error.py
Normal file
74
tests/core/test_backend_error.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from vibe.core.llm.exceptions import BackendError, PayloadSummary
|
||||
|
||||
|
||||
def _make_payload_summary() -> PayloadSummary:
|
||||
return PayloadSummary(
|
||||
model="test-model",
|
||||
message_count=1,
|
||||
approx_chars=10,
|
||||
temperature=0.7,
|
||||
has_tools=False,
|
||||
tool_choice=None,
|
||||
)
|
||||
|
||||
|
||||
def _make_error(
|
||||
*, status: int | None, headers: dict[str, str] | None = None
|
||||
) -> BackendError:
|
||||
return BackendError(
|
||||
provider="test-provider",
|
||||
endpoint="/v1/chat/completions",
|
||||
status=status,
|
||||
reason="some reason",
|
||||
headers=headers or {},
|
||||
body_text="body",
|
||||
parsed_error=None,
|
||||
model="test-model",
|
||||
payload_summary=_make_payload_summary(),
|
||||
)
|
||||
|
||||
|
||||
class TestBackendErrorFmt:
|
||||
def test_standard_status_code(self) -> None:
|
||||
err = _make_error(status=500)
|
||||
msg = str(err)
|
||||
assert "500 Internal Server Error" in msg
|
||||
assert "test-provider" in msg
|
||||
|
||||
def test_non_standard_status_code(self) -> None:
|
||||
"""Status 529 is not in HTTPStatus and previously raised ValueError."""
|
||||
err = _make_error(status=529)
|
||||
msg = str(err)
|
||||
assert "529" in msg
|
||||
# Should not contain a phrase since 529 is not standard
|
||||
assert "LLM backend error [test-provider]" in msg
|
||||
|
||||
def test_no_status(self) -> None:
|
||||
err = _make_error(status=None)
|
||||
msg = str(err)
|
||||
assert "status: N/A" in msg
|
||||
|
||||
def test_unauthorized_short_circuits(self) -> None:
|
||||
err = _make_error(status=401)
|
||||
assert str(err) == "Invalid API key. Please check your API key and try again."
|
||||
|
||||
def test_rate_limit_short_circuits(self) -> None:
|
||||
err = _make_error(status=429)
|
||||
assert (
|
||||
str(err) == "Rate limit exceeded. Please wait a moment before trying again."
|
||||
)
|
||||
|
||||
def test_request_id_from_headers(self) -> None:
|
||||
err = _make_error(status=500, headers={"x-request-id": "req-123"})
|
||||
assert "req-123" in str(err)
|
||||
|
||||
@pytest.mark.parametrize("code", [530, 599, 999])
|
||||
def test_other_non_standard_codes(self, code: int) -> None:
|
||||
err = _make_error(status=code)
|
||||
msg = str(err)
|
||||
assert str(code) in msg
|
||||
assert "LLM backend error" in msg
|
||||
31
tests/core/test_retry.py
Normal file
31
tests/core/test_retry.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from vibe.core.utils.retry import _is_retryable_http_error
|
||||
|
||||
|
||||
def _make_http_status_error(status_code: int) -> httpx.HTTPStatusError:
|
||||
response = httpx.Response(
|
||||
status_code=status_code, request=httpx.Request("GET", "https://example.com")
|
||||
)
|
||||
return httpx.HTTPStatusError(
|
||||
message=f"Error {status_code}", request=response.request, response=response
|
||||
)
|
||||
|
||||
|
||||
class TestIsRetryableHttpError:
|
||||
@pytest.mark.parametrize("code", [408, 409, 425, 429, 500, 502, 503, 504, 529])
|
||||
def test_retryable_codes(self, code: int) -> None:
|
||||
assert _is_retryable_http_error(_make_http_status_error(code)) is True
|
||||
|
||||
@pytest.mark.parametrize("code", [400, 401, 403, 404, 422])
|
||||
def test_non_retryable_codes(self, code: int) -> None:
|
||||
assert _is_retryable_http_error(_make_http_status_error(code)) is False
|
||||
|
||||
def test_non_http_error_returns_false(self) -> None:
|
||||
assert _is_retryable_http_error(ValueError("not http")) is False
|
||||
|
||||
def test_generic_exception_returns_false(self) -> None:
|
||||
assert _is_retryable_http_error(RuntimeError("boom")) is False
|
||||
Loading…
Add table
Add a link
Reference in a new issue