Fix a type error when using google-genai==1.7.0 (#141431)

* Fix parts

* Fix the type being sent to the SDK

* Revert changes to __init__

* Test fixes

* Bump version back to 1.7
This commit is contained in:
Ivan Lopez Hernandez 2025-03-25 19:59:21 -07:00 committed by GitHub
parent 2208650fde
commit 56cc4044e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 77 additions and 75 deletions

View File

@ -171,17 +171,25 @@ def _escape_decode(value: Any) -> Any:
return value return value
def _create_google_tool_response_parts(
parts: list[conversation.ToolResultContent],
) -> list[Part]:
"""Create Google tool response parts."""
return [
Part.from_function_response(
name=tool_result.tool_name, response=tool_result.tool_result
)
for tool_result in parts
]
def _create_google_tool_response_content( def _create_google_tool_response_content(
content: list[conversation.ToolResultContent], content: list[conversation.ToolResultContent],
) -> Content: ) -> Content:
"""Create a Google tool response content.""" """Create a Google tool response content."""
return Content( return Content(
parts=[ role="user",
Part.from_function_response( parts=_create_google_tool_response_parts(content),
name=tool_result.tool_name, response=tool_result.tool_result
)
for tool_result in content
]
) )
@ -402,7 +410,7 @@ class GoogleGenerativeAIConversationEntity(
chat = self._genai_client.aio.chats.create( chat = self._genai_client.aio.chats.create(
model=model_name, history=messages, config=generateContentConfig model=model_name, history=messages, config=generateContentConfig
) )
chat_request: str | Content = user_input.text chat_request: str | list[Part] = user_input.text
# To prevent infinite loops, we limit the number of iterations # To prevent infinite loops, we limit the number of iterations
for _iteration in range(MAX_TOOL_ITERATIONS): for _iteration in range(MAX_TOOL_ITERATIONS):
try: try:
@ -456,7 +464,7 @@ class GoogleGenerativeAIConversationEntity(
) )
) )
chat_request = _create_google_tool_response_content( chat_request = _create_google_tool_response_parts(
[ [
tool_response tool_response
async for tool_response in chat_log.async_add_assistant_content( async for tool_response in chat_log.async_add_assistant_content(

View File

@ -25,7 +25,9 @@
tuple( tuple(
), ),
dict({ dict({
'message': Content(parts=[Part(video_metadata=None, thought=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None, function_response=FunctionResponse(id=None, name='test_tool', response={'result': 'Test response'}), inline_data=None, text=None)], role=None), 'message': list([
Part(video_metadata=None, thought=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None, function_response=FunctionResponse(id=None, name='test_tool', response={'result': 'Test response'}), inline_data=None, text=None),
]),
}), }),
), ),
]) ])
@ -56,7 +58,9 @@
tuple( tuple(
), ),
dict({ dict({
'message': Content(parts=[Part(video_metadata=None, thought=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None, function_response=FunctionResponse(id=None, name='test_tool', response={'result': 'Test response'}), inline_data=None, text=None)], role=None), 'message': list([
Part(video_metadata=None, thought=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None, function_response=FunctionResponse(id=None, name='test_tool', response={'result': 'Test response'}), inline_data=None, text=None),
]),
}), }),
), ),
]) ])
@ -87,7 +91,9 @@
tuple( tuple(
), ),
dict({ dict({
'message': Content(parts=[Part(video_metadata=None, thought=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None, function_response=FunctionResponse(id=None, name='test_tool', response={'result': 'Test response'}), inline_data=None, text=None)], role=None), 'message': list([
Part(video_metadata=None, thought=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None, function_response=FunctionResponse(id=None, name='test_tool', response={'result': 'Test response'}), inline_data=None, text=None),
]),
}), }),
), ),
]) ])

View File

@ -104,28 +104,24 @@ async def test_function_call(
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
assert result.response.as_dict()["speech"]["plain"]["speech"] == "Hi there!" assert result.response.as_dict()["speech"]["plain"]["speech"] == "Hi there!"
mock_tool_call = mock_create.mock_calls[2][2]["message"] mock_tool_response_parts = mock_create.mock_calls[2][2]["message"]
assert mock_tool_call.model_dump() == { assert len(mock_tool_response_parts) == 1
"parts": [ assert mock_tool_response_parts[0].model_dump() == {
{ "code_execution_result": None,
"code_execution_result": None, "executable_code": None,
"executable_code": None, "file_data": None,
"file_data": None, "function_call": None,
"function_call": None, "function_response": {
"function_response": { "id": None,
"id": None, "name": "test_tool",
"name": "test_tool", "response": {
"response": { "result": "Test response",
"result": "Test response",
},
},
"inline_data": None,
"text": None,
"thought": None,
"video_metadata": None,
}, },
], },
"role": None, "inline_data": None,
"text": None,
"thought": None,
"video_metadata": None,
} }
mock_tool.async_call.assert_awaited_once_with( mock_tool.async_call.assert_awaited_once_with(
@ -292,28 +288,24 @@ async def test_function_call_without_parameters(
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
assert result.response.as_dict()["speech"]["plain"]["speech"] == "Hi there!" assert result.response.as_dict()["speech"]["plain"]["speech"] == "Hi there!"
mock_tool_call = mock_create.mock_calls[2][2]["message"] mock_tool_response_parts = mock_create.mock_calls[2][2]["message"]
assert mock_tool_call.model_dump() == { assert len(mock_tool_response_parts) == 1
"parts": [ assert mock_tool_response_parts[0].model_dump() == {
{ "code_execution_result": None,
"code_execution_result": None, "executable_code": None,
"executable_code": None, "file_data": None,
"file_data": None, "function_call": None,
"function_call": None, "function_response": {
"function_response": { "id": None,
"id": None, "name": "test_tool",
"name": "test_tool", "response": {
"response": { "result": "Test response",
"result": "Test response",
},
},
"inline_data": None,
"text": None,
"thought": None,
"video_metadata": None,
}, },
], },
"role": None, "inline_data": None,
"text": None,
"thought": None,
"video_metadata": None,
} }
mock_tool.async_call.assert_awaited_once_with( mock_tool.async_call.assert_awaited_once_with(
@ -390,29 +382,25 @@ async def test_function_exception(
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
assert result.response.as_dict()["speech"]["plain"]["speech"] == "Hi there!" assert result.response.as_dict()["speech"]["plain"]["speech"] == "Hi there!"
mock_tool_call = mock_create.mock_calls[2][2]["message"] mock_tool_response_parts = mock_create.mock_calls[2][2]["message"]
assert mock_tool_call.model_dump() == { assert len(mock_tool_response_parts) == 1
"parts": [ assert mock_tool_response_parts[0].model_dump() == {
{ "code_execution_result": None,
"code_execution_result": None, "executable_code": None,
"executable_code": None, "file_data": None,
"file_data": None, "function_call": None,
"function_call": None, "function_response": {
"function_response": { "id": None,
"id": None, "name": "test_tool",
"name": "test_tool", "response": {
"response": { "error": "HomeAssistantError",
"error": "HomeAssistantError", "error_text": "Test tool exception",
"error_text": "Test tool exception",
},
},
"inline_data": None,
"text": None,
"thought": None,
"video_metadata": None,
}, },
], },
"role": None, "inline_data": None,
"text": None,
"thought": None,
"video_metadata": None,
} }
mock_tool.async_call.assert_awaited_once_with( mock_tool.async_call.assert_awaited_once_with(
hass, hass,