fix(core): raise LLMEmptyResponseError for empty Anthropic responses (#9624)

* fix(core): raise LLMEmptyResponseError for empty Anthropic responses

Fixes LET-7679: Opus 4.6 occasionally returns empty responses (no content
and no tool calls), causing silent failures with stop_reason=end_turn.

Changes:
- Add LLMEmptyResponseError class (subclass of LLMServerError)
- Raise error in anthropic_client for empty non-streaming responses
- Raise error in anthropic_streaming_interface for empty streaming responses
- Pass through LLMError instances in handle_llm_error to preserve specific types
- Add test for empty streaming response detection

This allows clients (letta-code) to catch this specific error and implement
retry logic with cache-busting modifications.

🤖 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

* fix(core): set invalid_llm_response stop reason for empty responses

Catch LLMEmptyResponseError specifically and set stop_reason to
invalid_llm_response instead of llm_api_error. This allows clients
to distinguish empty responses from transient API errors.

🤖 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

---------

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
cthomas
2026-02-24 19:57:23 -08:00
committed by Caren Thomas
parent 86ff216dc9
commit 3d781efd21
5 changed files with 116 additions and 6 deletions

View File

@@ -283,6 +283,15 @@ class LLMServerError(LLMError):
while processing the request."""
class LLMEmptyResponseError(LLMServerError):
"""Error when LLM returns an empty response (no content and no tool calls).
This is a subclass of LLMServerError to maintain retry behavior, but allows
specific handling for empty response cases which may benefit from request
modification before retry.
"""
class LLMTimeoutError(LLMError):
"""Error when LLM request times out"""