-
Notifications
You must be signed in to change notification settings - Fork 16
[BUGS] Prevent NullPointerException for Gemini models with empty AIMessage content #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Adds a check for empty message content before processing in GenericProvider, returning a default text when content is missing.
|
@luigisaetta Does this resolve your issue? |
| # Issue 78 fix: Check if original content is empty BEFORE processing | ||
| # to prevent NullPointerException in OCI backend | ||
| else: | ||
| content = [self.oci_chat_message_text_content(text=".")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so there has to be an arbitrary character in the the text?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I tried to use an empty space as the content, but empty space does not work.
|
Should this PR be merged with: #81? |
Gemini tool calls work with non-empty content field. |
|
Hey @paxiaatucsdedu, thanks for working on this fix! I wanted to share some test results that might be helpful. I ran integration tests to check the full tool calling flow with Gemini, and found that the empty content fix alone may not be enough for the complete agentic loop. Test EvidenceTest 1: GenericProvider (current approach) - FAILS Test 2: GeminiProvider (PR #81 approach) - SUCCEEDS Issues Found
SuggestionIn PR #81, I worked around these OCI translation limitations by converting tool-related messages to regular user/assistant messages. This has 38 passing integration tests including real agent workflows. Would it make sense to combine our efforts? Happy to discuss! |
|
Hi @fede-kamel, thank you for testing it. I tested with the test python script from this issue description. Gemini works with no problem as long as the content is not empty, and the Gemini model response is very similar to the grok-4 model (Grok-4 is mentioned in the issue description as working properly). This is the Jupyter notebook I used for testing with PR #79 |
|
Here's the minimal test code to reproduce: from langchain_core.messages import HumanMessage, ToolMessage
from langchain_core.tools import tool
from langchain_oci.chat_models import ChatOCIGenAI
@tool
def get_weather(city: str) -> str:
"""Get weather for a city."""
return f"Sunny, 22°C in {city}"
# Create LLM with tools
llm = ChatOCIGenAI(model_id="google.gemini-2.5-flash", ...)
llm_with_tools = llm.bind_tools([get_weather])
# Step 1: Get tool calls (works)
messages = [HumanMessage(content="What's the weather in Rome?")]
response = llm_with_tools.invoke(messages)
# Returns: tool_calls=[{'name': 'get_weather', 'args': {'city': 'Rome'}, 'id': None}]
# Step 2: Send tool result back (fails)
messages.append(response)
messages.append(ToolMessage(
content="Sunny, 22°C in Rome",
tool_call_id="call_get_weather", # Note: Gemini returned id=None
name="get_weather",
))
final = llm_with_tools.invoke(messages) # 💥 400 errorThe error occurs because OCI can't translate |
|
Hi @paxiaatucsdedu! Thanks for sharing the notebook - it helped me understand your test setup better. I did some additional testing and found something interesting. The notebook test works because it uses a manually constructed conversation history with a hardcoded # From notebook - REQUEST 2
AIMessage(content="", tool_calls=[{"id": "call_ed2635c686f449eea25915b2", ...}])
ToolMessage(content="<tool_response!>", tool_call_id="call_ed2635c686f449eea25915b2")However, when I tested the real agentic flow (asking Gemini, getting its response, executing tool, sending result back), I found that Gemini actually returns So the issue is:
Your empty content fix is valid and needed (Test 1→2 in my earlier tests), but there's this additional Happy to share the test script if you'd like to reproduce this on your end! |
|
And just to show how PR #81 addresses this - the # Instead of sending ToolMessage (which OCI can't translate for Gemini)
# GeminiProvider converts it to a UserMessage:
ToolMessage(content="Sunny, 22°C")
→ UserMessage(content="Function get_weather returned: Sunny, 22°C")
# And AIMessage with tool_calls (where id=None is a problem)
# becomes a regular AssistantMessage:
AIMessage(content="", tool_calls=[{id: None, name: "get_weather", ...}])
→ AssistantMessage(content="I'll call get_weather with arguments: {\"city\": \"Rome\"}")This bypasses both issues:
Same test with GeminiProvider: Both PRs could work together - your fix handles the empty content edge case, and the GeminiProvider handles the message format translation. What do you think? |
Problem
When using Google Gemini models with tool calling,
AIMessageswith empty content (content="") cause aTransientServiceError(HTTP 500) due to a NullPointerException in the OCI backend when converting messages to Google's format.Issue link: #78
Solution
Check for empty content in AIMessages with tool calls before processing, and provide a minimal placeholder (
.) to prevent null serialization. This follows the same pattern used by the Cohere provider.Testing
Tested with
google.gemini-2.5-flashmodel using AIMessage with empty content and tool calls - error is now resolved.Model response:
content='The weather in Rome is currently sunny with a temperature of 20 degrees Celsius.' additional_kwargs={'finish_reason': 'stop'} response_metadata={'finish_reason': 'stop'} id='run--68c2e374-d8eb-43be-aec2-de2815789dc4-0'