Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion keep/providers/litellm_provider/litellm_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def _query(
# Extract the generated text from the response
try:
generated_text = result["choices"][0]["message"]["content"]
except KeyError:
except (KeyError, IndexError):
generated_text = ""

# Reasoning models return content=None when the whole max_tokens
Expand Down
2 changes: 1 addition & 1 deletion keep/providers/vllm_provider/vllm_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def _query(
# Adjust this based on your vLLM API response structure
try:
generated_text = result["choices"][0]['text']
except KeyError:
except (KeyError, IndexError):
generated_text = ""

# Try to parse as JSON if it's meant to be structured
Expand Down
19 changes: 19 additions & 0 deletions tests/providers/litellm_provider/test_litellm_response_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,22 @@ def test_missing_usage_does_not_break_the_response():
assert result["prompt_tokens"] is None
assert result["cost"] is None
assert result["model"] == "local-model"


def _empty_choices_response():
"""Some OpenAI-compatible backends (e.g. Azure content filtering) return
HTTP 200 with an empty ``choices`` list. ``raise_for_status`` passes, so the
provider still has to read ``choices[0]``."""
response = MagicMock()
response.raise_for_status = MagicMock()
response.json = MagicMock(return_value={"choices": []})
return response


def test_empty_choices_does_not_crash():
# choices[0] on an empty list raises IndexError, which the old
# ``except KeyError`` did not catch, so the step died with an opaque
# traceback instead of an empty response.
provider = _build_provider()
with patch("requests.post", return_value=_empty_choices_response()):
assert provider._query(prompt="hi")["response"] == ""
Loading