From 0288213fbfa935c9bf9d56416619ea929ae1cf63 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:15:22 +0000 Subject: [PATCH 1/8] feat(client): send `X-Stainless-Read-Timeout` header (#2094) --- src/openai/_base_client.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 1fa039c0b1..8a408d8e58 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -420,10 +420,17 @@ def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0 if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers: headers[idempotency_header] = options.idempotency_key or self._idempotency_key() - # Don't set the retry count header if it was already set or removed by the caller. We check + # Don't set these headers if they were already set or removed by the caller. We check # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case. - if "x-stainless-retry-count" not in (header.lower() for header in custom_headers): + lower_custom_headers = [header.lower() for header in custom_headers] + if "x-stainless-retry-count" not in lower_custom_headers: headers["x-stainless-retry-count"] = str(retries_taken) + if "x-stainless-read-timeout" not in lower_custom_headers: + timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout + if isinstance(timeout, Timeout): + timeout = timeout.read + if timeout is not None: + headers["x-stainless-read-timeout"] = str(timeout) return headers From e0ca9f0f6fae40230f8cab97573914ed632920b6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:25:56 +0000 Subject: [PATCH 2/8] fix(api): add missing reasoning effort + model enums (#2096) --- .stats.yml | 2 +- src/openai/resources/beta/assistants.py | 106 +++++++++++++++++- src/openai/resources/beta/chat/completions.py | 8 +- .../resources/beta/threads/runs/runs.py | 68 +++++++++++ src/openai/resources/chat/completions.py | 28 ++--- .../types/beta/assistant_create_params.py | 11 +- .../types/beta/assistant_update_params.py | 47 +++++++- .../types/beta/threads/run_create_params.py | 9 ++ .../chat/chat_completion_reasoning_effort.py | 3 +- .../types/chat/completion_create_params.py | 4 +- tests/api_resources/beta/test_assistants.py | 8 +- tests/api_resources/beta/threads/test_runs.py | 4 + 12 files changed, 268 insertions(+), 30 deletions(-) diff --git a/.stats.yml b/.stats.yml index df7877dfd0..8a5d2c06b2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 69 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-fc5dbc19505b0035f9e7f88868619f4fb519b048bde011f6154f3132d4be71fb.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-7c699d4503077d06a4a44f52c0c1f902d19a87c766b8be75b97c8dfd484ad4aa.yml diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 65b7c9cfc2..462086f74b 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -61,6 +61,7 @@ def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_resources: Optional[assistant_create_params.ToolResources] | NotGiven = NOT_GIVEN, @@ -97,6 +98,13 @@ def create( name: The name of the assistant. The maximum length is 256 characters. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -155,6 +163,7 @@ def create( "instructions": instructions, "metadata": metadata, "name": name, + "reasoning_effort": reasoning_effort, "response_format": response_format, "temperature": temperature, "tool_resources": tool_resources, @@ -210,8 +219,42 @@ def update( description: Optional[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: str | NotGiven = NOT_GIVEN, + model: Union[ + str, + Literal[ + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-mini", + "gpt-4o-mini-2024-07-18", + "gpt-4-turbo", + "gpt-4-turbo-2024-04-09", + "gpt-4-0125-preview", + "gpt-4-turbo-preview", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-4", + "gpt-4-0314", + "gpt-4-0613", + "gpt-4-32k", + "gpt-4-32k-0314", + "gpt-4-32k-0613", + "gpt-3.5-turbo", + "gpt-3.5-turbo-16k", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613", + ], + ] + | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_resources: Optional[assistant_update_params.ToolResources] | NotGiven = NOT_GIVEN, @@ -249,6 +292,13 @@ def update( name: The name of the assistant. The maximum length is 256 characters. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -309,6 +359,7 @@ def update( "metadata": metadata, "model": model, "name": name, + "reasoning_effort": reasoning_effort, "response_format": response_format, "temperature": temperature, "tool_resources": tool_resources, @@ -451,6 +502,7 @@ async def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_resources: Optional[assistant_create_params.ToolResources] | NotGiven = NOT_GIVEN, @@ -487,6 +539,13 @@ async def create( name: The name of the assistant. The maximum length is 256 characters. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -545,6 +604,7 @@ async def create( "instructions": instructions, "metadata": metadata, "name": name, + "reasoning_effort": reasoning_effort, "response_format": response_format, "temperature": temperature, "tool_resources": tool_resources, @@ -600,8 +660,42 @@ async def update( description: Optional[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: str | NotGiven = NOT_GIVEN, + model: Union[ + str, + Literal[ + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-mini", + "gpt-4o-mini-2024-07-18", + "gpt-4-turbo", + "gpt-4-turbo-2024-04-09", + "gpt-4-0125-preview", + "gpt-4-turbo-preview", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-4", + "gpt-4-0314", + "gpt-4-0613", + "gpt-4-32k", + "gpt-4-32k-0314", + "gpt-4-32k-0613", + "gpt-3.5-turbo", + "gpt-3.5-turbo-16k", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613", + ], + ] + | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_resources: Optional[assistant_update_params.ToolResources] | NotGiven = NOT_GIVEN, @@ -639,6 +733,13 @@ async def update( name: The name of the assistant. The maximum length is 256 characters. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -699,6 +800,7 @@ async def update( "metadata": metadata, "model": model, "name": name, + "reasoning_effort": reasoning_effort, "response_format": response_format, "temperature": temperature, "tool_resources": tool_resources, diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 8a3a20d9e0..0c631b9821 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -83,7 +83,7 @@ def parse( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, @@ -228,7 +228,7 @@ def stream( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, @@ -358,7 +358,7 @@ async def parse( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, @@ -503,7 +503,7 @@ def stream( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 13301ad507..dc364b4e31 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -96,6 +96,7 @@ def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -164,6 +165,13 @@ def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -239,6 +247,7 @@ def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -310,6 +319,13 @@ def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -381,6 +397,7 @@ def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -452,6 +469,13 @@ def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -522,6 +546,7 @@ def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -552,6 +577,7 @@ def create( "metadata": metadata, "model": model, "parallel_tool_calls": parallel_tool_calls, + "reasoning_effort": reasoning_effort, "response_format": response_format, "stream": stream, "temperature": temperature, @@ -774,6 +800,7 @@ def create_and_poll( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -809,6 +836,7 @@ def create_and_poll( temperature=temperature, tool_choice=tool_choice, parallel_tool_calls=parallel_tool_calls, + reasoning_effort=reasoning_effort, # We assume we are not streaming when polling stream=False, tools=tools, @@ -843,6 +871,7 @@ def create_and_stream( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -874,6 +903,7 @@ def create_and_stream( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -905,6 +935,7 @@ def create_and_stream( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -950,6 +981,7 @@ def create_and_stream( "tools": tools, "truncation_strategy": truncation_strategy, "parallel_tool_calls": parallel_tool_calls, + "reasoning_effort": reasoning_effort, "top_p": top_p, }, run_create_params.RunCreateParams, @@ -1022,6 +1054,7 @@ def stream( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1053,6 +1086,7 @@ def stream( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1084,6 +1118,7 @@ def stream( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1128,6 +1163,7 @@ def stream( "stream": True, "tools": tools, "parallel_tool_calls": parallel_tool_calls, + "reasoning_effort": reasoning_effort, "truncation_strategy": truncation_strategy, "top_p": top_p, }, @@ -1469,6 +1505,7 @@ async def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1537,6 +1574,13 @@ async def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -1612,6 +1656,7 @@ async def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1683,6 +1728,13 @@ async def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -1754,6 +1806,7 @@ async def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1825,6 +1878,13 @@ async def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + reasoning_effort: **o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), @@ -1895,6 +1955,7 @@ async def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1925,6 +1986,7 @@ async def create( "metadata": metadata, "model": model, "parallel_tool_calls": parallel_tool_calls, + "reasoning_effort": reasoning_effort, "response_format": response_format, "stream": stream, "temperature": temperature, @@ -2147,6 +2209,7 @@ async def create_and_poll( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -2182,6 +2245,7 @@ async def create_and_poll( temperature=temperature, tool_choice=tool_choice, parallel_tool_calls=parallel_tool_calls, + reasoning_effort=reasoning_effort, # We assume we are not streaming when polling stream=False, tools=tools, @@ -2396,6 +2460,7 @@ def stream( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -2427,6 +2492,7 @@ def stream( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -2458,6 +2524,7 @@ def stream( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -2504,6 +2571,7 @@ def stream( "stream": True, "tools": tools, "parallel_tool_calls": parallel_tool_calls, + "reasoning_effort": reasoning_effort, "truncation_strategy": truncation_strategy, "top_p": top_p, }, diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index 34f6b50301..cc839103a0 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -82,7 +82,7 @@ def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -213,7 +213,7 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - reasoning_effort: **o1 models only** + reasoning_effort: **o1 and o3-mini models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -335,7 +335,7 @@ def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -472,7 +472,7 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - reasoning_effort: **o1 models only** + reasoning_effort: **o1 and o3-mini models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -587,7 +587,7 @@ def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -724,7 +724,7 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - reasoning_effort: **o1 models only** + reasoning_effort: **o1 and o3-mini models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -838,7 +838,7 @@ def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -946,7 +946,7 @@ async def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -1077,7 +1077,7 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - reasoning_effort: **o1 models only** + reasoning_effort: **o1 and o3-mini models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1199,7 +1199,7 @@ async def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -1336,7 +1336,7 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - reasoning_effort: **o1 models only** + reasoning_effort: **o1 and o3-mini models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1451,7 +1451,7 @@ async def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -1588,7 +1588,7 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - reasoning_effort: **o1 models only** + reasoning_effort: **o1 and o3-mini models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1702,7 +1702,7 @@ async def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: ChatCompletionReasoningEffort | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index e205856395..66bef02ced 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import List, Union, Iterable, Optional -from typing_extensions import Required, TypedDict +from typing_extensions import Literal, Required, TypedDict from ..chat_model import ChatModel from .assistant_tool_param import AssistantToolParam @@ -53,6 +53,15 @@ class AssistantCreateParams(TypedDict, total=False): name: Optional[str] """The name of the assistant. The maximum length is 256 characters.""" + reasoning_effort: Optional[Literal["low", "medium", "high"]] + """**o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + """ + response_format: Optional[AssistantResponseFormatOptionParam] """Specifies the format that the model must output. diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 35065ef61b..80fec110cd 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -2,8 +2,8 @@ from __future__ import annotations -from typing import List, Iterable, Optional -from typing_extensions import TypedDict +from typing import List, Union, Iterable, Optional +from typing_extensions import Literal, TypedDict from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata @@ -32,7 +32,39 @@ class AssistantUpdateParams(TypedDict, total=False): a maximum length of 512 characters. """ - model: str + model: Union[ + str, + Literal[ + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-mini", + "gpt-4o-mini-2024-07-18", + "gpt-4-turbo", + "gpt-4-turbo-2024-04-09", + "gpt-4-0125-preview", + "gpt-4-turbo-preview", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-4", + "gpt-4-0314", + "gpt-4-0613", + "gpt-4-32k", + "gpt-4-32k-0314", + "gpt-4-32k-0613", + "gpt-3.5-turbo", + "gpt-3.5-turbo-16k", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613", + ], + ] """ID of the model to use. You can use the @@ -45,6 +77,15 @@ class AssistantUpdateParams(TypedDict, total=False): name: Optional[str] """The name of the assistant. The maximum length is 256 characters.""" + reasoning_effort: Optional[Literal["low", "medium", "high"]] + """**o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + """ + response_format: Optional[AssistantResponseFormatOptionParam] """Specifies the format that the model must output. diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 091dd3da66..093b4ce321 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -106,6 +106,15 @@ class RunCreateParamsBase(TypedDict, total=False): during tool use. """ + reasoning_effort: Optional[Literal["low", "medium", "high"]] + """**o1 and o3-mini models only** + + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + result in faster responses and fewer tokens used on reasoning in a response. + """ + response_format: Optional[AssistantResponseFormatOptionParam] """Specifies the format that the model must output. diff --git a/src/openai/types/chat/chat_completion_reasoning_effort.py b/src/openai/types/chat/chat_completion_reasoning_effort.py index 9e7946974a..85249c53b1 100644 --- a/src/openai/types/chat/chat_completion_reasoning_effort.py +++ b/src/openai/types/chat/chat_completion_reasoning_effort.py @@ -1,7 +1,8 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional from typing_extensions import Literal, TypeAlias __all__ = ["ChatCompletionReasoningEffort"] -ChatCompletionReasoningEffort: TypeAlias = Literal["low", "medium", "high"] +ChatCompletionReasoningEffort: TypeAlias = Optional[Literal["low", "medium", "high"]] diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index ec88ea1fb0..c761cbe07b 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -174,8 +174,8 @@ class CompletionCreateParamsBase(TypedDict, total=False): far, increasing the model's likelihood to talk about new topics. """ - reasoning_effort: ChatCompletionReasoningEffort - """**o1 models only** + reasoning_effort: Optional[ChatCompletionReasoningEffort] + """**o1 and o3-mini models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index 458e3f5e90..82aaf87b1c 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -36,6 +36,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: instructions="instructions", metadata={"foo": "string"}, name="name", + reasoning_effort="low", response_format="auto", temperature=1, tool_resources={ @@ -132,8 +133,9 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: description="description", instructions="instructions", metadata={"foo": "string"}, - model="model", + model="string", name="name", + reasoning_effort="low", response_format="auto", temperature=1, tool_resources={ @@ -268,6 +270,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> instructions="instructions", metadata={"foo": "string"}, name="name", + reasoning_effort="low", response_format="auto", temperature=1, tool_resources={ @@ -364,8 +367,9 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> description="description", instructions="instructions", metadata={"foo": "string"}, - model="model", + model="string", name="name", + reasoning_effort="low", response_format="auto", temperature=1, tool_resources={ diff --git a/tests/api_resources/beta/threads/test_runs.py b/tests/api_resources/beta/threads/test_runs.py index 48b39cfe5b..d05ee96144 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -56,6 +56,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, + reasoning_effort="low", response_format="auto", stream=False, temperature=1, @@ -139,6 +140,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, + reasoning_effort="low", response_format="auto", temperature=1, tool_choice="none", @@ -552,6 +554,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, + reasoning_effort="low", response_format="auto", stream=False, temperature=1, @@ -635,6 +638,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, + reasoning_effort="low", response_format="auto", temperature=1, tool_choice="none", From 9a95db9154ac98678970e7f1652a7cacfd2f7fdb Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Thu, 6 Feb 2025 21:15:14 +1100 Subject: [PATCH 3/8] feat(embeddings): use stdlib array type for improved performance (#2060) --- src/openai/resources/embeddings.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 382a42340e..a392d5eb17 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -2,6 +2,7 @@ from __future__ import annotations +import array import base64 from typing import List, Union, Iterable, cast from typing_extensions import Literal @@ -102,7 +103,7 @@ def create( "dimensions": dimensions, "encoding_format": encoding_format, } - if not is_given(encoding_format) and has_numpy(): + if not is_given(encoding_format): params["encoding_format"] = "base64" def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: @@ -113,12 +114,14 @@ def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: for embedding in obj.data: data = cast(object, embedding.embedding) if not isinstance(data, str): - # numpy is not installed / base64 optimisation isn't enabled for this model yet continue - - embedding.embedding = np.frombuffer( # type: ignore[no-untyped-call] - base64.b64decode(data), dtype="float32" - ).tolist() + if not has_numpy(): + # use array for base64 optimisation + embedding.embedding = array.array("f", base64.b64decode(data)).tolist() + else: + embedding.embedding = np.frombuffer( # type: ignore[no-untyped-call] + base64.b64decode(data), dtype="float32" + ).tolist() return obj @@ -215,7 +218,7 @@ async def create( "dimensions": dimensions, "encoding_format": encoding_format, } - if not is_given(encoding_format) and has_numpy(): + if not is_given(encoding_format): params["encoding_format"] = "base64" def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: @@ -226,12 +229,14 @@ def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: for embedding in obj.data: data = cast(object, embedding.embedding) if not isinstance(data, str): - # numpy is not installed / base64 optimisation isn't enabled for this model yet continue - - embedding.embedding = np.frombuffer( # type: ignore[no-untyped-call] - base64.b64decode(data), dtype="float32" - ).tolist() + if not has_numpy(): + # use array for base64 optimisation + embedding.embedding = array.array("f", base64.b64decode(data)).tolist() + else: + embedding.embedding = np.frombuffer( # type: ignore[no-untyped-call] + base64.b64decode(data), dtype="float32" + ).tolist() return obj From 4e5b368bf576f38d0f125778edde74ed6d101d7d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:00:22 +0000 Subject: [PATCH 4/8] chore(internal): fix type traversing dictionary params (#2097) --- src/openai/_utils/_transform.py | 12 +++++++++++- tests/test_transform.py | 11 ++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index a6b62cad0c..18afd9d8bd 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -25,7 +25,7 @@ is_annotated_type, strip_annotated_type, ) -from .._compat import model_dump, is_typeddict +from .._compat import get_origin, model_dump, is_typeddict _T = TypeVar("_T") @@ -164,9 +164,14 @@ def _transform_recursive( inner_type = annotation stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type if is_typeddict(stripped_type) and is_mapping(data): return _transform_typeddict(data, stripped_type) + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + if ( # List[T] (is_list_type(stripped_type) and is_list(data)) @@ -307,9 +312,14 @@ async def _async_transform_recursive( inner_type = annotation stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type if is_typeddict(stripped_type) and is_mapping(data): return await _async_transform_typeddict(data, stripped_type) + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + if ( # List[T] (is_list_type(stripped_type) and is_list(data)) diff --git a/tests/test_transform.py b/tests/test_transform.py index 8c6aba6448..385fbe2b2c 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -2,7 +2,7 @@ import io import pathlib -from typing import Any, List, Union, TypeVar, Iterable, Optional, cast +from typing import Any, Dict, List, Union, TypeVar, Iterable, Optional, cast from datetime import date, datetime from typing_extensions import Required, Annotated, TypedDict @@ -388,6 +388,15 @@ def my_iter() -> Iterable[Baz8]: } +@parametrize +@pytest.mark.asyncio +async def test_dictionary_items(use_async: bool) -> None: + class DictItems(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + assert await transform({"foo": {"foo_baz": "bar"}}, Dict[str, DictItems], use_async) == {"foo": {"fooBaz": "bar"}} + + class TypedDictIterableUnionStr(TypedDict): foo: Annotated[Union[str, Iterable[Baz8]], PropertyInfo(alias="FOO")] From 18824832d3a676ae49206cd2b5e09d4796fdf033 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:16:44 +0000 Subject: [PATCH 5/8] feat(pagination): avoid fetching when has_more: false (#2098) --- .stats.yml | 2 +- src/openai/pagination.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 8a5d2c06b2..d59a86d22e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 69 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-7c699d4503077d06a4a44f52c0c1f902d19a87c766b8be75b97c8dfd484ad4aa.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-dfb00c627f58e5180af7a9b29ed2f2aa0764a3b9daa6a32a1cc45bc8e48dfe15.yml diff --git a/src/openai/pagination.py b/src/openai/pagination.py index 8293638269..a59cced854 100644 --- a/src/openai/pagination.py +++ b/src/openai/pagination.py @@ -61,6 +61,7 @@ def next_page_info(self) -> None: class SyncCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): data: List[_T] + has_more: Optional[bool] = None @override def _get_page_items(self) -> List[_T]: @@ -69,6 +70,14 @@ def _get_page_items(self) -> List[_T]: return [] return data + @override + def has_next_page(self) -> bool: + has_more = self.has_more + if has_more is not None and has_more is False: + return False + + return super().has_next_page() + @override def next_page_info(self) -> Optional[PageInfo]: data = self.data @@ -85,6 +94,7 @@ def next_page_info(self) -> Optional[PageInfo]: class AsyncCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): data: List[_T] + has_more: Optional[bool] = None @override def _get_page_items(self) -> List[_T]: @@ -93,6 +103,14 @@ def _get_page_items(self) -> List[_T]: return [] return data + @override + def has_next_page(self) -> bool: + has_more = self.has_more + if has_more is not None and has_more is False: + return False + + return super().has_next_page() + @override def next_page_info(self) -> Optional[PageInfo]: data = self.data From a2c6da0fbc610ee80a2e044a0b20fc1cc2376962 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:22:46 +0000 Subject: [PATCH 6/8] chore(internal): minor type handling changes (#2099) --- src/openai/_models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index c6e1305087..92986bfdf5 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -451,10 +451,16 @@ def construct_type(*, value: object, type_: object) -> object: If the given value does not match the expected type then it is returned as-is. """ + + # store a reference to the original type we were given before we extract any inner + # types so that we can properly resolve forward references in `TypeAliasType` annotations + original_type = None + # we allow `object` as the input type because otherwise, passing things like # `Literal['value']` will be reported as a type error by type checkers type_ = cast("type[object]", type_) if is_type_alias_type(type_): + original_type = type_ # type: ignore[unreachable] type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` @@ -471,7 +477,7 @@ def construct_type(*, value: object, type_: object) -> object: if is_union(origin): try: - return validate_type(type_=cast("type[object]", type_), value=value) + return validate_type(type_=cast("type[object]", original_type or type_), value=value) except Exception: pass From 8e748bb08d9c0d1f7e8a1af31452e25eb7154f55 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 10 Feb 2025 18:08:55 +0000 Subject: [PATCH 7/8] fix(parsing): don't default to an empty array (#2106) --- src/openai/lib/_parsing/_completions.py | 2 +- tests/lib/chat/test_completions.py | 22 ++++++++++---------- tests/lib/chat/test_completions_streaming.py | 20 +++++++++--------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index 33c4ccb946..14b1745d3d 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -111,7 +111,7 @@ def parse_chat_completion( response_format=response_format, message=message, ), - "tool_calls": tool_calls, + "tool_calls": tool_calls if tool_calls else None, }, }, ) diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index 48f41eb221..74cee27b93 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -65,7 +65,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte parsed=None, refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ], @@ -132,7 +132,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=65.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ], @@ -201,7 +201,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=65.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ], @@ -272,7 +272,7 @@ class ColorDetection(BaseModel): parsed=ColorDetection(color=, hex_color_code='#FF0000'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) """ @@ -321,7 +321,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=64.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ), ParsedChoice[Location]( @@ -335,7 +335,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=65.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ), ParsedChoice[Location]( @@ -349,7 +349,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=63.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ] @@ -399,7 +399,7 @@ class CalendarEvent: parsed=CalendarEvent(name='Science Fair', date='Friday', participants=['Alice', 'Bob']), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ], @@ -571,7 +571,7 @@ class Location(BaseModel): parsed=None, refusal="I'm very sorry, but I can't assist with that.", role='assistant', - tool_calls=[] + tool_calls=None ) ) ] @@ -855,7 +855,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=58.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ], @@ -930,7 +930,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=65.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ], diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 1eed031af7..71b4173738 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -70,7 +70,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte parsed=None, refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ] @@ -147,7 +147,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream parsed=Location(city='San Francisco', temperature=61.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ], @@ -324,7 +324,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=65.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ), ParsedChoice[Location]( @@ -338,7 +338,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=61.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ), ParsedChoice[Location]( @@ -352,7 +352,7 @@ class Location(BaseModel): parsed=Location(city='San Francisco', temperature=59.0, units='f'), refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ] @@ -427,7 +427,7 @@ class Location(BaseModel): parsed=None, refusal="I'm sorry, I can't assist with that request.", role='assistant', - tool_calls=[] + tool_calls=None ) ) ] @@ -501,7 +501,7 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp parsed=None, refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ] @@ -612,7 +612,7 @@ class Location(BaseModel): parsed=None, refusal="I'm very sorry, but I can't assist with that.", role='assistant', - tool_calls=[] + tool_calls=None ) ) ] @@ -925,7 +925,7 @@ def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, mo parsed=None, refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ] @@ -1040,7 +1040,7 @@ def streamer(client: OpenAI) -> Iterator[ChatCompletionChunk]: parsed=None, refusal=None, role='assistant', - tool_calls=[] + tool_calls=None ) ) ] From d9b74c2407d897180ed7ce53d3f2087e95923a6f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 05:04:25 +0000 Subject: [PATCH 8/8] release: 1.62.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 22 ++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 285741ee32..ccd8ea8be5 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.61.1" + ".": "1.62.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 101e7480b7..583fbd9add 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 1.62.0 (2025-02-12) + +Full Changelog: [v1.61.1...v1.62.0](https://github.com/openai/openai-python/compare/v1.61.1...v1.62.0) + +### Features + +* **client:** send `X-Stainless-Read-Timeout` header ([#2094](https://github.com/openai/openai-python/issues/2094)) ([0288213](https://github.com/openai/openai-python/commit/0288213fbfa935c9bf9d56416619ea929ae1cf63)) +* **embeddings:** use stdlib array type for improved performance ([#2060](https://github.com/openai/openai-python/issues/2060)) ([9a95db9](https://github.com/openai/openai-python/commit/9a95db9154ac98678970e7f1652a7cacfd2f7fdb)) +* **pagination:** avoid fetching when has_more: false ([#2098](https://github.com/openai/openai-python/issues/2098)) ([1882483](https://github.com/openai/openai-python/commit/18824832d3a676ae49206cd2b5e09d4796fdf033)) + + +### Bug Fixes + +* **api:** add missing reasoning effort + model enums ([#2096](https://github.com/openai/openai-python/issues/2096)) ([e0ca9f0](https://github.com/openai/openai-python/commit/e0ca9f0f6fae40230f8cab97573914ed632920b6)) +* **parsing:** don't default to an empty array ([#2106](https://github.com/openai/openai-python/issues/2106)) ([8e748bb](https://github.com/openai/openai-python/commit/8e748bb08d9c0d1f7e8a1af31452e25eb7154f55)) + + +### Chores + +* **internal:** fix type traversing dictionary params ([#2097](https://github.com/openai/openai-python/issues/2097)) ([4e5b368](https://github.com/openai/openai-python/commit/4e5b368bf576f38d0f125778edde74ed6d101d7d)) +* **internal:** minor type handling changes ([#2099](https://github.com/openai/openai-python/issues/2099)) ([a2c6da0](https://github.com/openai/openai-python/commit/a2c6da0fbc610ee80a2e044a0b20fc1cc2376962)) + ## 1.61.1 (2025-02-05) Full Changelog: [v1.61.0...v1.61.1](https://github.com/openai/openai-python/compare/v1.61.0...v1.61.1) diff --git a/pyproject.toml b/pyproject.toml index 6f1a6eb28a..85cb145673 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.61.1" +version = "1.62.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_version.py b/src/openai/_version.py index 7ffe16b95d..7dd5163b53 100644 --- a/src/openai/_version.py +++ b/src/openai/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "openai" -__version__ = "1.61.1" # x-release-please-version +__version__ = "1.62.0" # x-release-please-version