From d07a908297f5be2eeafb200454aec269eb395ff6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 May 2026 03:21:40 -0500 Subject: [PATCH 1/2] fix: guard against empty/filtered LLM responses in get_first_message_content Add null checks in openai_client.py and azureai_client.py before accessing choices[0].message.content. Empty choices causes IndexError; None message (some providers on filtered content with HTTP 200) causes AttributeError. --- api/azureai_client.py | 2 ++ api/openai_client.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/api/azureai_client.py b/api/azureai_client.py index 948e86c30..13f06709a 100644 --- a/api/azureai_client.py +++ b/api/azureai_client.py @@ -75,6 +75,8 @@ def get_first_message_content(completion: ChatCompletion) -> str: r"""When we only need the content of the first message. It is the default parser for chat completion.""" + if not completion.choices or completion.choices[0].message is None: + raise ValueError("LLM returned empty or filtered response") return completion.choices[0].message.content diff --git a/api/openai_client.py b/api/openai_client.py index bc75ed586..5a145d751 100644 --- a/api/openai_client.py +++ b/api/openai_client.py @@ -59,6 +59,8 @@ def get_first_message_content(completion: ChatCompletion) -> str: r"""When we only need the content of the first message. It is the default parser for chat completion.""" log.debug(f"raw completion: {completion}") + if not completion.choices or completion.choices[0].message is None: + raise ValueError("LLM returned empty or filtered response") return completion.choices[0].message.content From 17a147799474c437450f8b61530c7863f05f7677 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 May 2026 10:41:47 -0500 Subject: [PATCH 2/2] fix: also guard against None message.content in get_first_message_content message.content can be None when the model returns a tool call or when content is filtered (HTTP 200 with null content field). Without this check the function silently returns None instead of raising ValueError. Addresses Gemini code review feedback on PR #524. --- api/azureai_client.py | 6 +++++- api/openai_client.py | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/api/azureai_client.py b/api/azureai_client.py index 13f06709a..5d70e5cee 100644 --- a/api/azureai_client.py +++ b/api/azureai_client.py @@ -75,7 +75,11 @@ def get_first_message_content(completion: ChatCompletion) -> str: r"""When we only need the content of the first message. It is the default parser for chat completion.""" - if not completion.choices or completion.choices[0].message is None: + if ( + not completion.choices + or completion.choices[0].message is None + or completion.choices[0].message.content is None + ): raise ValueError("LLM returned empty or filtered response") return completion.choices[0].message.content diff --git a/api/openai_client.py b/api/openai_client.py index 5a145d751..afa4059ad 100644 --- a/api/openai_client.py +++ b/api/openai_client.py @@ -59,7 +59,11 @@ def get_first_message_content(completion: ChatCompletion) -> str: r"""When we only need the content of the first message. It is the default parser for chat completion.""" log.debug(f"raw completion: {completion}") - if not completion.choices or completion.choices[0].message is None: + if ( + not completion.choices + or completion.choices[0].message is None + or completion.choices[0].message.content is None + ): raise ValueError("LLM returned empty or filtered response") return completion.choices[0].message.content