Skip to content

Commit 369db3f

Browse files
committed
fix: validate sync chat stream tools
1 parent afbb292 commit 369db3f

2 files changed

Lines changed: 11 additions & 20 deletions

File tree

src/openai/resources/chat/completions/completions.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
ResponseFormatT,
3838
validate_input_tools as _validate_input_tools,
3939
parse_chat_completion as _parse_chat_completion,
40-
materialize_input_tools as _materialize_input_tools,
4140
type_to_response_format_param as _type_to_response_format,
4241
)
4342
from ....lib.streaming.chat import ChatCompletionStreamManager, AsyncChatCompletionStreamManager
@@ -1613,7 +1612,7 @@ def stream(
16131612
When the context manager exits, the response will be closed, however the `stream` instance is still available outside
16141613
the context manager.
16151614
"""
1616-
chat_completion_tools = _materialize_input_tools(tools)
1615+
chat_completion_tools = _validate_input_tools(tools)
16171616

16181617
extra_headers = {
16191618
"X-Stainless-Helper-Method": "chat.completions.stream",

tests/lib/chat/test_single_pass_tools.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -138,24 +138,16 @@ def test_stream_preserves_single_pass_tools(client: OpenAI, respx2_mock: MockRou
138138
assert_request_and_parsed_tool(respx2_mock, tool_calls[0].function.parsed_arguments)
139139

140140

141-
@pytest.mark.respx2(base_url=base_url)
142-
def test_stream_preserves_non_strict_single_pass_tools(client: OpenAI, respx2_mock: MockRouter) -> None:
143-
respx2_mock.post("/chat/completions").mock(
144-
return_value=httpx2.Response(200, text=STREAM_RESPONSE, headers={"content-type": "text/event-stream"})
145-
)
146-
147-
with client.chat.completions.stream(
148-
model="gpt-test",
149-
messages=[{"role": "user", "content": "weather"}],
150-
tools=non_strict_tools(),
151-
) as stream:
152-
completion = stream.get_final_completion()
153-
154-
tool_calls = completion.choices[0].message.tool_calls
155-
assert tool_calls is not None
156-
body = json.loads(cast("list[MockRequestCall]", respx2_mock.calls)[0].request.content)
157-
assert body["tools"] == list(non_strict_tools())
158-
assert tool_calls[0].function.parsed_arguments is None
141+
def test_stream_rejects_non_strict_single_pass_tools(client: OpenAI) -> None:
142+
with pytest.raises(
143+
ValueError,
144+
match=r"`get_weather` is not strict\. Only `strict` function tools can be auto-parsed",
145+
):
146+
client.chat.completions.stream(
147+
model="gpt-test",
148+
messages=[{"role": "user", "content": "weather"}],
149+
tools=non_strict_tools(),
150+
)
159151

160152

161153
@pytest.mark.respx2(base_url=base_url)

0 commit comments

Comments
 (0)