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):
|
if isinstance(event.item, ResponseOutputMessage):
|
||||||
yield {"role": event.item.role}
|
yield {"role": event.item.role}
|
||||||
elif isinstance(event.item, ResponseFunctionToolCall):
|
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
|
current_tool_call = event.item
|
||||||
elif isinstance(event, ResponseOutputItemDoneEvent):
|
elif isinstance(event, ResponseOutputItemDoneEvent):
|
||||||
item = event.item.model_dump()
|
item = event.item.model_dump()
|
||||||
|
@ -17,13 +17,6 @@
|
|||||||
}),
|
}),
|
||||||
'tool_name': 'test_tool',
|
'tool_name': 'test_tool',
|
||||||
}),
|
}),
|
||||||
dict({
|
|
||||||
'id': 'call_call_2',
|
|
||||||
'tool_args': dict({
|
|
||||||
'param1': 'call2',
|
|
||||||
}),
|
|
||||||
'tool_name': 'test_tool',
|
|
||||||
}),
|
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
@ -33,6 +26,20 @@
|
|||||||
'tool_name': 'test_tool',
|
'tool_name': 'test_tool',
|
||||||
'tool_result': 'value1',
|
'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({
|
dict({
|
||||||
'agent_id': 'conversation.openai',
|
'agent_id': 'conversation.openai',
|
||||||
'role': 'tool_result',
|
'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
|
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(
|
@pytest.mark.parametrize(
|
||||||
("description", "messages"),
|
("description", "messages"),
|
||||||
[
|
[
|
||||||
|
Loading…
x
Reference in New Issue
Block a user