mirror of
https://github.com/deepset-ai/haystack.git
synced 2026-01-06 12:07:04 +00:00
fix: in OpenAIChatGenerator set additionalProperties to False when tools_strict=True (#8913)
* fix: set ComponentTool addtionalProperties for OpenAI tools_strict=True * add reno * Move the additionalProperties into the OpenAIChatGenerator * Remove * Put additionalProperties into the correct place * Fix test * Update releasenotes/notes/fix-componenttool-for-openai-tools_strict-998e5cd7ebc6ec19.yaml Co-authored-by: Stefano Fiorucci <stefanofiorucci@gmail.com> --------- Co-authored-by: Sebastian Husch Lee <sebastian.lee@deepset.ai> Co-authored-by: Sebastian Husch Lee <sjrl@users.noreply.github.com> Co-authored-by: Stefano Fiorucci <stefanofiorucci@gmail.com>
This commit is contained in:
parent
296e31c182
commit
13968cc15b
@ -373,10 +373,13 @@ class OpenAIChatGenerator:
|
||||
|
||||
openai_tools = {}
|
||||
if tools:
|
||||
tool_definitions = [
|
||||
{"type": "function", "function": {**t.tool_spec, **({"strict": tools_strict} if tools_strict else {})}}
|
||||
for t in tools
|
||||
]
|
||||
tool_definitions = []
|
||||
for t in tools:
|
||||
function_spec = {**t.tool_spec}
|
||||
if tools_strict:
|
||||
function_spec["strict"] = True
|
||||
function_spec["parameters"]["additionalProperties"] = False
|
||||
tool_definitions.append({"type": "function", "function": function_spec})
|
||||
openai_tools = {"tools": tool_definitions}
|
||||
|
||||
is_streaming = streaming_callback is not None
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Make sure that `OpenAIChatGenerator` sets `additionalProperties: False` in the tool schema when `tool_strict` is set to `True`.
|
||||
@ -407,9 +407,10 @@ class TestOpenAIChatGenerator:
|
||||
response = component.run([ChatMessage.from_user("What's the weather like in Paris?")])
|
||||
|
||||
# ensure that the tools are passed to the OpenAI API
|
||||
assert mock_chat_completion_create.call_args[1]["tools"] == [
|
||||
{"type": "function", "function": {**tools[0].tool_spec, "strict": True}}
|
||||
]
|
||||
function_spec = {**tools[0].tool_spec}
|
||||
function_spec["strict"] = True
|
||||
function_spec["parameters"]["additionalProperties"] = False
|
||||
assert mock_chat_completion_create.call_args[1]["tools"] == [{"type": "function", "function": function_spec}]
|
||||
|
||||
assert len(response["replies"]) == 1
|
||||
message = response["replies"][0]
|
||||
|
||||
@ -216,9 +216,10 @@ class TestOpenAIChatGeneratorAsync:
|
||||
response = await component.run_async([ChatMessage.from_user("What's the weather like in Paris?")])
|
||||
|
||||
# ensure that the tools are passed to the OpenAI API
|
||||
assert mock_chat_completion_create.call_args[1]["tools"] == [
|
||||
{"type": "function", "function": {**tools[0].tool_spec, "strict": True}}
|
||||
]
|
||||
function_spec = {**tools[0].tool_spec}
|
||||
function_spec["strict"] = True
|
||||
function_spec["parameters"]["additionalProperties"] = False
|
||||
assert mock_chat_completion_create.call_args[1]["tools"] == [{"type": "function", "function": function_spec}]
|
||||
|
||||
assert len(response["replies"]) == 1
|
||||
message = response["replies"][0]
|
||||
|
||||
@ -346,6 +346,37 @@ class TestToolComponentInPipelineWithOpenAI:
|
||||
assert "Vladimir" in tool_message.tool_call_result.result
|
||||
assert not tool_message.tool_call_result.error
|
||||
|
||||
@pytest.mark.skipif(not os.environ.get("OPENAI_API_KEY"), reason="OPENAI_API_KEY not set")
|
||||
@pytest.mark.integration
|
||||
def test_component_tool_in_pipeline_openai_tools_strict(self):
|
||||
# Create component and convert it to tool
|
||||
component = SimpleComponent()
|
||||
tool = ComponentTool(
|
||||
component=component, name="hello_tool", description="A tool that generates a greeting message for the user"
|
||||
)
|
||||
|
||||
# Create pipeline with OpenAIChatGenerator and ToolInvoker
|
||||
pipeline = Pipeline()
|
||||
pipeline.add_component("llm", OpenAIChatGenerator(model="gpt-4o-mini", tools=[tool], tools_strict=True))
|
||||
pipeline.add_component("tool_invoker", ToolInvoker(tools=[tool]))
|
||||
|
||||
# Connect components
|
||||
pipeline.connect("llm.replies", "tool_invoker.messages")
|
||||
|
||||
message = ChatMessage.from_user(text="Vladimir")
|
||||
|
||||
# Run pipeline
|
||||
result = pipeline.run({"llm": {"messages": [message]}})
|
||||
|
||||
# Check results
|
||||
tool_messages = result["tool_invoker"]["tool_messages"]
|
||||
assert len(tool_messages) == 1
|
||||
|
||||
tool_message = tool_messages[0]
|
||||
assert tool_message.is_from(ChatRole.TOOL)
|
||||
assert "Vladimir" in tool_message.tool_call_result.result
|
||||
assert not tool_message.tool_call_result.error
|
||||
|
||||
@pytest.mark.skipif(not os.environ.get("OPENAI_API_KEY"), reason="OPENAI_API_KEY not set")
|
||||
@pytest.mark.integration
|
||||
def test_user_greeter_in_pipeline(self):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user