mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-22 21:28:12 +02:00
feat(error-handling): implement LLM error adaptation and classification for chat streaming
- Introduced LLMErrorCategory and adapt_llm_exception to normalize LLM exceptions. - Updated llm_retryable_message and llm_permanent_message to utilize the new adaptation logic. - Enhanced classify_stream_exception to classify provider errors and return user-friendly messages. - Added tests for error classification and adaptation to ensure robustness. - Updated frontend error handling to display appropriate messages based on new classifications.
This commit is contained in:
parent
203ef78346
commit
8e8cf96faa
9 changed files with 533 additions and 38 deletions
|
|
@ -0,0 +1,80 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from app.services.llm_error_adapter import LLMErrorCategory, adapt_llm_exception
|
||||
from app.tasks.chat.streaming.errors.classifier import classify_stream_exception
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
|
||||
def _exception_named(name: str, message: str) -> Exception:
|
||||
return type(name, (Exception,), {})(message)
|
||||
|
||||
|
||||
def test_adapter_classifies_authentication_error_by_class_name() -> None:
|
||||
exc = _exception_named("AuthenticationError", "provider rejected credentials")
|
||||
|
||||
adapted = adapt_llm_exception(exc)
|
||||
|
||||
assert adapted.category is LLMErrorCategory.AUTH_FAILED
|
||||
assert adapted.retryable is False
|
||||
assert adapted.user_message == "LLM authentication failed. Check your API key."
|
||||
|
||||
|
||||
def test_adapter_classifies_embedded_provider_401_payload() -> None:
|
||||
exc = RuntimeError(
|
||||
'litellm.AuthenticationError: OpenrouterException - {"error":{"message":"User not found.","code":401}}'
|
||||
)
|
||||
|
||||
adapted = adapt_llm_exception(exc)
|
||||
|
||||
assert adapted.category is LLMErrorCategory.AUTH_FAILED
|
||||
assert adapted.provider_status_code == 401
|
||||
|
||||
|
||||
def test_adapter_preserves_rate_limit_classification() -> None:
|
||||
exc = RuntimeError('{"error":{"message":"Slow down","code":429}}')
|
||||
|
||||
adapted = adapt_llm_exception(exc)
|
||||
|
||||
assert adapted.category is LLMErrorCategory.RATE_LIMITED
|
||||
assert adapted.retryable is True
|
||||
|
||||
|
||||
def test_stream_classifier_maps_model_auth_to_stable_code() -> None:
|
||||
exc = RuntimeError(
|
||||
'litellm.AuthenticationError: OpenrouterException - {"error":{"message":"User not found.","code":401}}'
|
||||
)
|
||||
|
||||
kind, code, severity, expected, message, extra = classify_stream_exception(
|
||||
exc,
|
||||
flow_label="chat",
|
||||
)
|
||||
|
||||
assert kind == "model_auth_failed"
|
||||
assert code == "MODEL_AUTH_FAILED"
|
||||
assert severity == "warn"
|
||||
assert expected is True
|
||||
assert "API key" in message
|
||||
assert extra == {
|
||||
"provider_error_category": "auth_failed",
|
||||
"provider_status_code": 401,
|
||||
}
|
||||
|
||||
|
||||
def test_stream_classifier_keeps_unknown_errors_generic() -> None:
|
||||
exc = RuntimeError("database exploded")
|
||||
|
||||
kind, code, severity, expected, message, extra = classify_stream_exception(
|
||||
exc,
|
||||
flow_label="chat",
|
||||
)
|
||||
|
||||
assert kind == "server_error"
|
||||
assert code == "SERVER_ERROR"
|
||||
assert severity == "error"
|
||||
assert expected is False
|
||||
assert message == "Error during chat: database exploded"
|
||||
assert extra is None
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue