Bug Description
When using Gemini models (via direct API or ollama-cloud proxy), the agent fails with HTTP 400 "Request contains an invalid argument" errors. This happens because role: "tool" messages are missing the required name field.
The OpenAI API spec and Gemini's OpenAI-compatibility endpoint require the name field in tool response messages. While some providers (OpenAI, ollama) tolerate its absence, Gemini strictly enforces it.
Steps to Reproduce
- Configure hermes with a Gemini model as primary or fallback (e.g.,
gemini-3-flash-preview via ollama-cloud, or gemini-2.5-flash via direct Gemini API)
- Send a message that triggers tool use (e.g., a URL for web_extract)
- After a few tool call rounds, the accumulated conversation contains
tool messages without name
- Gemini API returns:
Error code: 400 - Request contains an invalid argument
Error Logs
⚠️ Non-retryable error (HTTP 400) — trying fallback...
🔄 Primary model failed — switching to fallback: gemini-2.5-flash via gemini
❌ Non-retryable error (HTTP 400): Error code: 400 - [{'error': {'code': 400, 'message': 'Request contains an invalid argument.', 'status': 'INVALID_ARGUMENT'}}]
Request dump shows tool messages like:
{"role": "tool", "tool_call_id": "call_xxx", "content": "..."}
Missing the required name field that Gemini expects.
Fix
Add the name field to all 9 locations in run_agent.py where role: "tool" messages are constructed. Also add a helper method _get_tool_call_name_static() to extract function names from both dict and object format tool calls.
Affected Locations in run_agent.py
- Line ~3751: Stub result for missing tool calls (sanitizer)
- Line ~7683: Interrupt skip in concurrent execution
- Line ~7951: Tool result in concurrent execution
- Line ~7977: Interrupt skip in sequential execution
- Line ~8309: Tool result in sequential execution
- Line ~8330: Interrupt skip in sequential execution
- Line ~10896: Invalid tool name error recovery
- Line ~10988: Invalid JSON arguments error recovery
- Line ~11479: Exception error handler
Patch
+ @staticmethod
+ def _get_tool_call_name_static(tc) -> str:
+ """Extract function name from a tool_call entry (dict or object)."""
+ if isinstance(tc, dict):
+ return tc.get("function", {}).get("name", "") or ""
+ return getattr(getattr(tc, "function", None), "name", "") or ""
Each tool message now includes "name": <function_name> alongside tool_call_id and content.
Environment
- hermes-agent: current main
- Models affected: All Gemini models (direct API + ollama-cloud proxy)
- Models unaffected: OpenAI, Anthropic, local ollama (tolerate missing
name)
Workaround
None — once the conversation accumulates tool messages without name, Gemini will keep rejecting the request until the session is cleared.
Bug Description
When using Gemini models (via direct API or ollama-cloud proxy), the agent fails with HTTP 400 "Request contains an invalid argument" errors. This happens because
role: "tool"messages are missing the requirednamefield.The OpenAI API spec and Gemini's OpenAI-compatibility endpoint require the
namefield in tool response messages. While some providers (OpenAI, ollama) tolerate its absence, Gemini strictly enforces it.Steps to Reproduce
gemini-3-flash-previewvia ollama-cloud, orgemini-2.5-flashvia direct Gemini API)toolmessages withoutnameError code: 400 - Request contains an invalid argumentError Logs
Request dump shows tool messages like:
{"role": "tool", "tool_call_id": "call_xxx", "content": "..."}Missing the required
namefield that Gemini expects.Fix
Add the
namefield to all 9 locations inrun_agent.pywhererole: "tool"messages are constructed. Also add a helper method_get_tool_call_name_static()to extract function names from both dict and object format tool calls.Affected Locations in
run_agent.pyPatch
Each tool message now includes
"name": <function_name>alongsidetool_call_idandcontent.Environment
name)Workaround
None — once the conversation accumulates tool messages without
name, Gemini will keep rejecting the request until the session is cleared.