mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Ensure that OpenAI tool call deltas have a role (#145085)
This commit is contained in:
parent
180e1f462c
commit
2956f4fea1
@ -141,6 +141,11 @@ async def _transform_stream(
|
||||
if isinstance(event.item, ResponseOutputMessage):
|
||||
yield {"role": event.item.role}
|
||||
elif isinstance(event.item, ResponseFunctionToolCall):
|
||||
# OpenAI has tool calls as individual events
|
||||
# while HA puts tool calls inside the assistant message.
|
||||
# We turn them into individual assistant content for HA
|
||||
# to ensure that tools are called as soon as possible.
|
||||
yield {"role": "assistant"}
|
||||
current_tool_call = event.item
|
||||
elif isinstance(event, ResponseOutputItemDoneEvent):
|
||||
item = event.item.model_dump()
|
||||
|
@ -17,13 +17,6 @@
|
||||
}),
|
||||
'tool_name': 'test_tool',
|
||||
}),
|
||||
dict({
|
||||
'id': 'call_call_2',
|
||||
'tool_args': dict({
|
||||
'param1': 'call2',
|
||||
}),
|
||||
'tool_name': 'test_tool',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
dict({
|
||||
@ -33,6 +26,20 @@
|
||||
'tool_name': 'test_tool',
|
||||
'tool_result': 'value1',
|
||||
}),
|
||||
dict({
|
||||
'agent_id': 'conversation.openai',
|
||||
'content': None,
|
||||
'role': 'assistant',
|
||||
'tool_calls': list([
|
||||
dict({
|
||||
'id': 'call_call_2',
|
||||
'tool_args': dict({
|
||||
'param1': 'call2',
|
||||
}),
|
||||
'tool_name': 'test_tool',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
dict({
|
||||
'agent_id': 'conversation.openai',
|
||||
'role': 'tool_result',
|
||||
@ -48,3 +55,38 @@
|
||||
}),
|
||||
])
|
||||
# ---
|
||||
# name: test_function_call_without_reasoning
|
||||
list([
|
||||
dict({
|
||||
'content': 'Please call the test function',
|
||||
'role': 'user',
|
||||
}),
|
||||
dict({
|
||||
'agent_id': 'conversation.openai',
|
||||
'content': None,
|
||||
'role': 'assistant',
|
||||
'tool_calls': list([
|
||||
dict({
|
||||
'id': 'call_call_1',
|
||||
'tool_args': dict({
|
||||
'param1': 'call1',
|
||||
}),
|
||||
'tool_name': 'test_tool',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
dict({
|
||||
'agent_id': 'conversation.openai',
|
||||
'role': 'tool_result',
|
||||
'tool_call_id': 'call_call_1',
|
||||
'tool_name': 'test_tool',
|
||||
'tool_result': 'value1',
|
||||
}),
|
||||
dict({
|
||||
'agent_id': 'conversation.openai',
|
||||
'content': 'Cool',
|
||||
'role': 'assistant',
|
||||
'tool_calls': None,
|
||||
}),
|
||||
])
|
||||
# ---
|
||||
|
@ -596,6 +596,48 @@ async def test_function_call(
|
||||
assert mock_chat_log.content[1:] == snapshot
|
||||
|
||||
|
||||
async def test_function_call_without_reasoning(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry_with_assist: MockConfigEntry,
|
||||
mock_init_component,
|
||||
mock_create_stream: AsyncMock,
|
||||
mock_chat_log: MockChatLog, # noqa: F811
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test function call from the assistant."""
|
||||
mock_create_stream.return_value = [
|
||||
# Initial conversation
|
||||
(
|
||||
*create_function_tool_call_item(
|
||||
id="fc_1",
|
||||
arguments=['{"para', 'm1":"call1"}'],
|
||||
call_id="call_call_1",
|
||||
name="test_tool",
|
||||
output_index=1,
|
||||
),
|
||||
),
|
||||
# Response after tool responses
|
||||
create_message_item(id="msg_A", text="Cool", output_index=0),
|
||||
]
|
||||
mock_chat_log.mock_tool_results(
|
||||
{
|
||||
"call_call_1": "value1",
|
||||
}
|
||||
)
|
||||
|
||||
result = await conversation.async_converse(
|
||||
hass,
|
||||
"Please call the test function",
|
||||
mock_chat_log.conversation_id,
|
||||
Context(),
|
||||
agent_id="conversation.openai",
|
||||
)
|
||||
|
||||
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
|
||||
# Don't test the prompt, as it's not deterministic
|
||||
assert mock_chat_log.content[1:] == snapshot
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("description", "messages"),
|
||||
[
|
||||
|
Loading…
x
Reference in New Issue
Block a user