feat: retry on empty LLM response (LET-7679) (#1130)

Co-authored-by: letta-code <248085862+letta-code@users.noreply.github.com>
Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
cthomas
2026-02-25 11:17:55 -08:00
committed by GitHub
parent 0023b9c7e5
commit be5fbfca74
5 changed files with 232 additions and 0 deletions

View File

@@ -5,6 +5,8 @@ import {
getPreStreamErrorAction,
isApprovalPendingError,
isConversationBusyError,
isEmptyResponseError,
isEmptyResponseRetryable,
isInvalidToolCallIdsError,
isNonRetryableProviderErrorDetail,
isRetryableProviderErrorDetail,
@@ -455,3 +457,90 @@ describe("shouldAttemptApprovalRecovery", () => {
expect(tuiResult).toBe(headlessResult);
});
});
// ── Empty response error detection (LET-7679) ────────────────────────
describe("isEmptyResponseError", () => {
test("detects empty content in response", () => {
expect(
isEmptyResponseError(
"LLM provider returned empty content in response (ID: msg_123, model: claude-opus-4-6)",
),
).toBe(true);
});
test("detects empty content in streaming response", () => {
expect(
isEmptyResponseError(
"LLM provider returned empty content in streaming response (model: claude-opus-4-6)",
),
).toBe(true);
});
test("case insensitive", () => {
expect(isEmptyResponseError("EMPTY CONTENT IN RESPONSE")).toBe(true);
});
test("returns false for unrelated errors", () => {
expect(isEmptyResponseError("Connection error")).toBe(false);
expect(isEmptyResponseError("Rate limit exceeded")).toBe(false);
});
test("returns false for non-string input", () => {
expect(isEmptyResponseError(null)).toBe(false);
expect(isEmptyResponseError(undefined)).toBe(false);
expect(isEmptyResponseError(123)).toBe(false);
});
});
describe("isEmptyResponseRetryable", () => {
test("true when llm_error and empty response detail and under retry budget", () => {
expect(
isEmptyResponseRetryable(
"llm_error",
"LLM provider returned empty content in response",
0,
2,
),
).toBe(true);
});
test("true at boundary (retries < max)", () => {
expect(
isEmptyResponseRetryable(
"llm_error",
"LLM provider returned empty content in streaming response",
1,
2,
),
).toBe(true);
});
test("false when retry budget exhausted", () => {
expect(
isEmptyResponseRetryable(
"llm_error",
"LLM provider returned empty content in response",
2,
2,
),
).toBe(false);
});
test("false when not llm_error type", () => {
expect(
isEmptyResponseRetryable(
"internal_error",
"LLM provider returned empty content in response",
0,
2,
),
).toBe(false);
});
test("false when not empty response error", () => {
expect(
isEmptyResponseRetryable("llm_error", "Connection error occurred", 0, 2),
).toBe(false);
});
});